LCOV - code coverage report
Current view: top level - resolve - resolved-dns-dnssec.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 371 1177 31.5 %
Date: 2019-08-23 13:36:53 Functions: 26 46 56.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 186 1091 17.0 %

           Branch data     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                 :        248 : 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         [ -  + ]:        248 :         assert(dnskey);
      47         [ -  + ]:        248 :         assert(dnskey->key->type == DNS_TYPE_DNSKEY);
      48                 :            : 
      49                 :        248 :         f = (uint32_t) dnskey->dnskey.flags;
      50                 :            : 
      51         [ +  + ]:        248 :         if (mask_revoke)
      52                 :        212 :                 f &= ~DNSKEY_FLAG_REVOKE;
      53                 :            : 
      54                 :        248 :         sum = f + ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
      55                 :            : 
      56                 :        248 :         p = dnskey->dnskey.key;
      57                 :            : 
      58         [ +  + ]:      48792 :         for (i = 0; i < dnskey->dnskey.key_size; i++)
      59         [ +  + ]:      48544 :                 sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i];
      60                 :            : 
      61                 :        248 :         sum += (sum >> 16) & UINT32_C(0xFFFF);
      62                 :            : 
      63                 :        248 :         return sum & UINT32_C(0xFFFF);
      64                 :            : }
      65                 :            : 
      66                 :         28 : int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
      67                 :         28 :         size_t c = 0;
      68                 :            :         int r;
      69                 :            : 
      70                 :            :         /* Converts the specified hostname into DNSSEC canonicalized
      71                 :            :          * form. */
      72                 :            : 
      73         [ -  + ]:         28 :         if (buffer_max < 2)
      74                 :          0 :                 return -ENOBUFS;
      75                 :            : 
      76                 :            :         for (;;) {
      77                 :         48 :                 r = dns_label_unescape(&n, buffer, buffer_max, 0);
      78         [ +  + ]:         48 :                 if (r < 0)
      79                 :          4 :                         return r;
      80         [ +  + ]:         44 :                 if (r == 0)
      81                 :         24 :                         break;
      82                 :            : 
      83         [ -  + ]:         20 :                 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         [ -  + ]:         20 :                 if (memchr(buffer, '.', r))
      91                 :          0 :                         return -EINVAL;
      92                 :            : 
      93                 :         20 :                 ascii_strlower_n(buffer, (size_t) r);
      94                 :         20 :                 buffer[r] = '.';
      95                 :            : 
      96                 :         20 :                 buffer += r + 1;
      97                 :         20 :                 c += r + 1;
      98                 :            : 
      99                 :         20 :                 buffer_max -= r + 1;
     100                 :            :         }
     101                 :            : 
     102         [ +  + ]:         24 :         if (c <= 0) {
     103                 :            :                 /* Not even a single label: this is the root domain name */
     104                 :            : 
     105         [ -  + ]:          8 :                 assert(buffer_max > 2);
     106                 :          8 :                 buffer[0] = '.';
     107                 :          8 :                 buffer[1] = 0;
     108                 :            : 
     109                 :          8 :                 return 1;
     110                 :            :         }
     111                 :            : 
     112                 :         16 :         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                 :          8 : 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                 :          8 :         gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
     146                 :          8 :         gcry_mpi_t n = NULL, e = NULL, s = NULL;
     147                 :            :         gcry_error_t ge;
     148                 :            :         int r;
     149                 :            : 
     150         [ -  + ]:          8 :         assert(hash_algorithm);
     151                 :            : 
     152                 :          8 :         ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
     153         [ -  + ]:          8 :         if (ge != 0) {
     154                 :          0 :                 r = -EIO;
     155                 :          0 :                 goto finish;
     156                 :            :         }
     157                 :            : 
     158                 :          8 :         ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
     159         [ -  + ]:          8 :         if (ge != 0) {
     160                 :          0 :                 r = -EIO;
     161                 :          0 :                 goto finish;
     162                 :            :         }
     163                 :            : 
     164                 :          8 :         ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
     165         [ -  + ]:          8 :         if (ge != 0) {
     166                 :          0 :                 r = -EIO;
     167                 :          0 :                 goto finish;
     168                 :            :         }
     169                 :            : 
     170                 :          8 :         ge = gcry_sexp_build(&signature_sexp,
     171                 :            :                              NULL,
     172                 :            :                              "(sig-val (rsa (s %m)))",
     173                 :            :                              s);
     174                 :            : 
     175         [ -  + ]:          8 :         if (ge != 0) {
     176                 :          0 :                 r = -EIO;
     177                 :          0 :                 goto finish;
     178                 :            :         }
     179                 :            : 
     180                 :          8 :         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         [ -  + ]:          8 :         if (ge != 0) {
     187                 :          0 :                 r = -EIO;
     188                 :          0 :                 goto finish;
     189                 :            :         }
     190                 :            : 
     191                 :          8 :         ge = gcry_sexp_build(&public_key_sexp,
     192                 :            :                              NULL,
     193                 :            :                              "(public-key (rsa (n %m) (e %m)))",
     194                 :            :                              n,
     195                 :            :                              e);
     196         [ -  + ]:          8 :         if (ge != 0) {
     197                 :          0 :                 r = -EIO;
     198                 :          0 :                 goto finish;
     199                 :            :         }
     200                 :            : 
     201                 :          8 :         ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
     202         [ -  + ]:          8 :         if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
     203                 :          0 :                 r = 0;
     204         [ -  + ]:          8 :         else if (ge != 0) {
     205         [ #  # ]:          0 :                 log_debug("RSA signature check failed: %s", gpg_strerror(ge));
     206                 :          0 :                 r = -EIO;
     207                 :            :         } else
     208                 :          8 :                 r = 1;
     209                 :            : 
     210                 :          8 : finish:
     211         [ +  - ]:          8 :         if (e)
     212                 :          8 :                 gcry_mpi_release(e);
     213         [ +  - ]:          8 :         if (n)
     214                 :          8 :                 gcry_mpi_release(n);
     215         [ +  - ]:          8 :         if (s)
     216                 :          8 :                 gcry_mpi_release(s);
     217                 :            : 
     218         [ +  - ]:          8 :         if (public_key_sexp)
     219                 :          8 :                 gcry_sexp_release(public_key_sexp);
     220         [ +  - ]:          8 :         if (signature_sexp)
     221                 :          8 :                 gcry_sexp_release(signature_sexp);
     222         [ +  - ]:          8 :         if (data_sexp)
     223                 :          8 :                 gcry_sexp_release(data_sexp);
     224                 :            : 
     225                 :          8 :         return r;
     226                 :            : }
     227                 :            : 
     228                 :          8 : 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         [ -  + ]:          8 :         assert(hash_algorithm);
     238         [ -  + ]:          8 :         assert(hash);
     239         [ -  + ]:          8 :         assert(hash_size > 0);
     240         [ -  + ]:          8 :         assert(rrsig);
     241         [ -  + ]:          8 :         assert(dnskey);
     242                 :            : 
     243         [ -  + ]:          8 :         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                 :          8 :                 exponent = (uint8_t*) dnskey->dnskey.key + 1;
     264                 :          8 :                 exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
     265                 :            : 
     266         [ -  + ]:          8 :                 if (exponent_size <= 0)
     267                 :          0 :                         return -EINVAL;
     268                 :            : 
     269         [ -  + ]:          8 :                 if (1 + exponent_size >= dnskey->dnskey.key_size)
     270                 :          0 :                         return -EINVAL;
     271                 :            : 
     272                 :          8 :                 modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
     273                 :          8 :                 modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
     274                 :            :         }
     275                 :            : 
     276                 :         16 :         return dnssec_rsa_verify_raw(
     277                 :            :                         hash_algorithm,
     278                 :          8 :                         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                 :          8 : 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                 :          8 :         gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
     427                 :            :         gcry_error_t ge;
     428                 :            :         int k;
     429                 :            : 
     430                 :          8 :         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         [ -  + ]:          8 :         if (ge != 0) {
     438                 :          0 :                 k = -EIO;
     439                 :          0 :                 goto finish;
     440                 :            :         }
     441                 :            : 
     442                 :          8 :         ge = gcry_sexp_build(&data_sexp,
     443                 :            :                              NULL,
     444                 :            :                              "(data (flags eddsa) (hash-algo sha512) (value %b))",
     445                 :            :                              (int) data_size,
     446                 :            :                              data);
     447         [ -  + ]:          8 :         if (ge != 0) {
     448                 :          0 :                 k = -EIO;
     449                 :          0 :                 goto finish;
     450                 :            :         }
     451                 :            : 
     452                 :          8 :         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         [ -  + ]:          8 :         if (ge != 0) {
     459                 :          0 :                 k = -EIO;
     460                 :          0 :                 goto finish;
     461                 :            :         }
     462                 :            : 
     463                 :          8 :         ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
     464         [ -  + ]:          8 :         if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
     465                 :          0 :                 k = 0;
     466         [ -  + ]:          8 :         else if (ge != 0) {
     467         [ #  # ]:          0 :                 log_debug("EdDSA signature check failed: %s", gpg_strerror(ge));
     468                 :          0 :                 k = -EIO;
     469                 :            :         } else
     470                 :          8 :                 k = 1;
     471                 :          8 : finish:
     472         [ +  - ]:          8 :         if (public_key_sexp)
     473                 :          8 :                 gcry_sexp_release(public_key_sexp);
     474         [ +  - ]:          8 :         if (signature_sexp)
     475                 :          8 :                 gcry_sexp_release(signature_sexp);
     476         [ +  - ]:          8 :         if (data_sexp)
     477                 :          8 :                 gcry_sexp_release(data_sexp);
     478                 :            : 
     479                 :          8 :         return k;
     480                 :            : }
     481                 :            : 
     482                 :          8 : 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         [ +  - ]:          8 :         if (algorithm == DNSSEC_ALGORITHM_ED25519) {
     491                 :          8 :                 curve = "Ed25519";
     492                 :          8 :                 key_size = 32;
     493                 :            :         } else
     494                 :          0 :                 return -EOPNOTSUPP;
     495                 :            : 
     496         [ -  + ]:          8 :         if (dnskey->dnskey.key_size != key_size)
     497                 :          0 :                 return -EINVAL;
     498                 :            : 
     499         [ -  + ]:          8 :         if (rrsig->rrsig.signature_size != key_size * 2)
     500                 :          0 :                 return -EINVAL;
     501                 :            : 
     502                 :         16 :         return dnssec_eddsa_verify_raw(
     503                 :            :                         curve,
     504                 :          8 :                         rrsig->rrsig.signature, key_size,
     505                 :          8 :                         (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
     506                 :            :                         data, data_size,
     507                 :          8 :                         dnskey->dnskey.key, key_size);
     508                 :            : }
     509                 :            : #endif
     510                 :            : 
     511                 :         16 : static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
     512                 :         16 :         gcry_md_write(md, &v, sizeof(v));
     513                 :         16 : }
     514                 :            : 
     515                 :          8 : static void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
     516                 :          8 :         v = htobe16(v);
     517                 :          8 :         gcry_md_write(md, &v, sizeof(v));
     518                 :          8 : }
     519                 :            : 
     520                 :         32 : static void fwrite_uint8(FILE *fp, uint8_t v) {
     521                 :         32 :         fwrite(&v, sizeof(v), 1, fp);
     522                 :         32 : }
     523                 :            : 
     524                 :         80 : static void fwrite_uint16(FILE *fp, uint16_t v) {
     525                 :         80 :         v = htobe16(v);
     526                 :         80 :         fwrite(&v, sizeof(v), 1, fp);
     527                 :         80 : }
     528                 :            : 
     529                 :         64 : static void fwrite_uint32(FILE *fp, uint32_t v) {
     530                 :         64 :         v = htobe32(v);
     531                 :         64 :         fwrite(&v, sizeof(v), 1, fp);
     532                 :         64 : }
     533                 :            : 
     534                 :         16 : 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         [ -  + ]:         16 :         assert(rrsig);
     543         [ -  + ]:         16 :         assert(rrsig->key->type == DNS_TYPE_RRSIG);
     544                 :            : 
     545                 :            :         /* Check if this RRSIG RR is already prepared */
     546         [ -  + ]:         16 :         if (rrsig->n_skip_labels_source != (unsigned) -1)
     547                 :          0 :                 return 0;
     548                 :            : 
     549         [ -  + ]:         16 :         if (rrsig->rrsig.inception > rrsig->rrsig.expiration)
     550                 :          0 :                 return -EINVAL;
     551                 :            : 
     552                 :         16 :         name = dns_resource_key_name(rrsig->key);
     553                 :            : 
     554                 :         16 :         n_key_labels = dns_name_count_labels(name);
     555         [ -  + ]:         16 :         if (n_key_labels < 0)
     556                 :          0 :                 return n_key_labels;
     557         [ -  + ]:         16 :         if (rrsig->rrsig.labels > n_key_labels)
     558                 :          0 :                 return -EINVAL;
     559                 :            : 
     560                 :         16 :         n_signer_labels = dns_name_count_labels(rrsig->rrsig.signer);
     561         [ -  + ]:         16 :         if (n_signer_labels < 0)
     562                 :          0 :                 return n_signer_labels;
     563         [ -  + ]:         16 :         if (n_signer_labels > rrsig->rrsig.labels)
     564                 :          0 :                 return -EINVAL;
     565                 :            : 
     566                 :         16 :         r = dns_name_skip(name, n_key_labels - n_signer_labels, &name);
     567         [ -  + ]:         16 :         if (r < 0)
     568                 :          0 :                 return r;
     569         [ -  + ]:         16 :         if (r == 0)
     570                 :          0 :                 return -EINVAL;
     571                 :            : 
     572                 :            :         /* Check if the signer is really a suffix of us */
     573                 :         16 :         r = dns_name_equal(name, rrsig->rrsig.signer);
     574         [ -  + ]:         16 :         if (r < 0)
     575                 :          0 :                 return r;
     576         [ -  + ]:         16 :         if (r == 0)
     577                 :          0 :                 return -EINVAL;
     578                 :            : 
     579                 :         16 :         rrsig->n_skip_labels_source = n_key_labels - rrsig->rrsig.labels;
     580                 :         16 :         rrsig->n_skip_labels_signer = n_key_labels - n_signer_labels;
     581                 :            : 
     582                 :         16 :         return 0;
     583                 :            : }
     584                 :            : 
     585                 :         16 : static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
     586                 :            :         usec_t expiration, inception, skew;
     587                 :            : 
     588         [ -  + ]:         16 :         assert(rrsig);
     589         [ -  + ]:         16 :         assert(rrsig->key->type == DNS_TYPE_RRSIG);
     590                 :            : 
     591         [ -  + ]:         16 :         if (realtime == USEC_INFINITY)
     592                 :          0 :                 realtime = now(CLOCK_REALTIME);
     593                 :            : 
     594                 :         16 :         expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
     595                 :         16 :         inception = rrsig->rrsig.inception * USEC_PER_SEC;
     596                 :            : 
     597                 :            :         /* Consider inverted validity intervals as expired */
     598         [ -  + ]:         16 :         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                 :         16 :         skew = (expiration - inception) / 10;
     605         [ +  - ]:         16 :         if (skew > SKEW_MAX)
     606                 :         16 :                 skew = SKEW_MAX;
     607                 :            : 
     608         [ -  + ]:         16 :         if (inception < skew)
     609                 :          0 :                 inception = 0;
     610                 :            :         else
     611                 :         16 :                 inception -= skew;
     612                 :            : 
     613         [ -  + ]:         16 :         if (expiration + skew < expiration)
     614                 :          0 :                 expiration = USEC_INFINITY;
     615                 :            :         else
     616                 :         16 :                 expiration += skew;
     617                 :            : 
     618   [ +  -  -  + ]:         16 :         return realtime < inception || realtime > expiration;
     619                 :            : }
     620                 :            : 
     621                 :          8 : 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   [ -  +  -  -  :          8 :         switch (algorithm) {
                      - ]
     634                 :            : 
     635                 :          0 :         case DNSSEC_ALGORITHM_RSASHA1:
     636                 :            :         case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
     637                 :          0 :                 return GCRY_MD_SHA1;
     638                 :            : 
     639                 :          8 :         case DNSSEC_ALGORITHM_RSASHA256:
     640                 :            :         case DNSSEC_ALGORITHM_ECDSAP256SHA256:
     641                 :          8 :                 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                 :         16 : 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         [ -  + ]:         16 :         assert(list);
     663         [ -  + ]:         16 :         assert(n > 0);
     664         [ -  + ]:         16 :         assert(rrsig);
     665                 :            : 
     666         [ +  + ]:         32 :         for (k = 0; k < n; k++) {
     667                 :         16 :                 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                 :         16 :                 rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl);
     673                 :         16 :                 rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
     674                 :            : 
     675                 :            :                 /* Copy over information about the signer and wildcard source of synthesis */
     676                 :         16 :                 rr->n_skip_labels_source = rrsig->n_skip_labels_source;
     677                 :         16 :                 rr->n_skip_labels_signer = rrsig->n_skip_labels_signer;
     678                 :            :         }
     679                 :            : 
     680                 :         16 :         rrsig->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
     681                 :         16 : }
     682                 :            : 
     683                 :         16 : 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                 :         16 :         _cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
     695                 :            :         int r, md_algorithm;
     696                 :         16 :         size_t k, n = 0;
     697                 :         16 :         size_t sig_size = 0;
     698                 :         16 :         _cleanup_free_ char *sig_data = NULL;
     699                 :         16 :         _cleanup_fclose_ FILE *f = NULL;
     700                 :            :         size_t hash_size;
     701                 :            :         void *hash;
     702                 :            :         bool wildcard;
     703                 :            : 
     704         [ -  + ]:         16 :         assert(key);
     705         [ -  + ]:         16 :         assert(rrsig);
     706         [ -  + ]:         16 :         assert(dnskey);
     707         [ -  + ]:         16 :         assert(result);
     708         [ -  + ]:         16 :         assert(rrsig->key->type == DNS_TYPE_RRSIG);
     709         [ -  + ]:         16 :         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                 :         16 :         r = dnssec_rrsig_prepare(rrsig);
     716         [ -  + ]:         16 :         if (r == -EINVAL) {
     717                 :          0 :                 *result = DNSSEC_INVALID;
     718                 :          0 :                 return r;
     719                 :            :         }
     720         [ -  + ]:         16 :         if (r < 0)
     721                 :          0 :                 return r;
     722                 :            : 
     723                 :         16 :         r = dnssec_rrsig_expired(rrsig, realtime);
     724         [ -  + ]:         16 :         if (r < 0)
     725                 :          0 :                 return r;
     726         [ -  + ]:         16 :         if (r > 0) {
     727                 :          0 :                 *result = DNSSEC_SIGNATURE_EXPIRED;
     728                 :          0 :                 return 0;
     729                 :            :         }
     730                 :            : 
     731                 :         16 :         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         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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                 :         16 :         r = dns_name_suffix(name, rrsig->rrsig.labels, &source);
     757         [ -  + ]:         16 :         if (r < 0)
     758                 :          0 :                 return r;
     759   [ -  +  #  # ]:         16 :         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         [ -  + ]:         16 :         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                 :         16 :                 wildcard = r > 0;
     776                 :            : 
     777                 :            :         /* Collect all relevant RRs in a single array, so that we can look at the RRset */
     778   [ -  +  -  + ]:         16 :         list = newa(DnsResourceRecord *, dns_answer_size(a));
     779                 :            : 
     780   [ +  -  +  -  :         32 :         DNS_ANSWER_FOREACH(rr, a) {
          -  +  +  -  +  
                      + ]
     781                 :         16 :                 r = dns_resource_key_equal(key, rr->key);
     782         [ -  + ]:         16 :                 if (r < 0)
     783                 :          0 :                         return r;
     784         [ -  + ]:         16 :                 if (r == 0)
     785                 :          0 :                         continue;
     786                 :            : 
     787                 :            :                 /* We need the wire format for ordering, and digest calculation */
     788                 :         16 :                 r = dns_resource_record_to_wire_format(rr, true);
     789         [ -  + ]:         16 :                 if (r < 0)
     790                 :          0 :                         return r;
     791                 :            : 
     792                 :         16 :                 list[n++] = rr;
     793                 :            : 
     794         [ -  + ]:         16 :                 if (n > VERIFY_RRS_MAX)
     795                 :          0 :                         return -E2BIG;
     796                 :            :         }
     797                 :            : 
     798         [ -  + ]:         16 :         if (n <= 0)
     799                 :          0 :                 return -ENODATA;
     800                 :            : 
     801                 :            :         /* Bring the RRs into canonical order */
     802                 :         16 :         typesafe_qsort(list, n, rr_compare);
     803                 :            : 
     804                 :         16 :         f = open_memstream_unlocked(&sig_data, &sig_size);
     805         [ -  + ]:         16 :         if (!f)
     806                 :          0 :                 return -ENOMEM;
     807                 :            : 
     808                 :         16 :         fwrite_uint16(f, rrsig->rrsig.type_covered);
     809                 :         16 :         fwrite_uint8(f, rrsig->rrsig.algorithm);
     810                 :         16 :         fwrite_uint8(f, rrsig->rrsig.labels);
     811                 :         16 :         fwrite_uint32(f, rrsig->rrsig.original_ttl);
     812                 :         16 :         fwrite_uint32(f, rrsig->rrsig.expiration);
     813                 :         16 :         fwrite_uint32(f, rrsig->rrsig.inception);
     814                 :         16 :         fwrite_uint16(f, rrsig->rrsig.key_tag);
     815                 :            : 
     816                 :         16 :         r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
     817         [ -  + ]:         16 :         if (r < 0)
     818                 :          0 :                 return r;
     819                 :         16 :         fwrite(wire_format_name, 1, r, f);
     820                 :            : 
     821                 :            :         /* Convert the source of synthesis into wire format */
     822                 :         16 :         r = dns_name_to_wire_format(source, wire_format_name, sizeof(wire_format_name), true);
     823         [ -  + ]:         16 :         if (r < 0)
     824                 :          0 :                 return r;
     825                 :            : 
     826         [ +  + ]:         32 :         for (k = 0; k < n; k++) {
     827                 :            :                 size_t l;
     828                 :            : 
     829                 :         16 :                 rr = list[k];
     830                 :            : 
     831                 :            :                 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
     832         [ -  + ]:         16 :                 if (wildcard)
     833                 :          0 :                         fwrite((uint8_t[]) { 1, '*'}, sizeof(uint8_t), 2, f);
     834                 :         16 :                 fwrite(wire_format_name, 1, r, f);
     835                 :            : 
     836                 :         16 :                 fwrite_uint16(f, rr->key->type);
     837                 :         16 :                 fwrite_uint16(f, rr->key->class);
     838                 :         16 :                 fwrite_uint32(f, rrsig->rrsig.original_ttl);
     839                 :            : 
     840                 :         16 :                 l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr);
     841         [ -  + ]:         16 :                 assert(l <= 0xFFFF);
     842                 :            : 
     843                 :         16 :                 fwrite_uint16(f, (uint16_t) l);
     844                 :         16 :                 fwrite(DNS_RESOURCE_RECORD_RDATA(rr), 1, l, f);
     845                 :            :         }
     846                 :            : 
     847                 :         16 :         r = fflush_and_check(f);
     848         [ -  + ]:         16 :         if (r < 0)
     849                 :          0 :                 return r;
     850                 :            : 
     851                 :         16 :         initialize_libgcrypt(false);
     852                 :            : 
     853      [ +  -  + ]:         16 :         switch (rrsig->rrsig.algorithm) {
     854                 :            : #if GCRYPT_VERSION_NUMBER >= 0x010600
     855                 :          8 :         case DNSSEC_ALGORITHM_ED25519:
     856                 :          8 :                 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                 :          8 :         default:
     864                 :            :                 /* OK, the RRs are now in canonical order. Let's calculate the digest */
     865                 :          8 :                 md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
     866         [ -  + ]:          8 :                 if (md_algorithm == -EOPNOTSUPP) {
     867                 :          0 :                         *result = DNSSEC_UNSUPPORTED_ALGORITHM;
     868                 :          0 :                         return 0;
     869                 :            :                 }
     870         [ -  + ]:          8 :                 if (md_algorithm < 0)
     871                 :          0 :                         return md_algorithm;
     872                 :            : 
     873                 :          8 :                 gcry_md_open(&md, md_algorithm, 0);
     874         [ -  + ]:          8 :                 if (!md)
     875                 :          0 :                         return -EIO;
     876                 :            : 
     877                 :          8 :                 hash_size = gcry_md_get_algo_dlen(md_algorithm);
     878         [ -  + ]:          8 :                 assert(hash_size > 0);
     879                 :            : 
     880                 :          8 :                 gcry_md_write(md, sig_data, sig_size);
     881                 :            : 
     882                 :          8 :                 hash = gcry_md_read(md, 0);
     883         [ -  + ]:          8 :                 if (!hash)
     884                 :          0 :                         return -EIO;
     885                 :            :         }
     886                 :            : 
     887   [ +  -  +  - ]:         16 :         switch (rrsig->rrsig.algorithm) {
     888                 :            : 
     889                 :          8 :         case DNSSEC_ALGORITHM_RSASHA1:
     890                 :            :         case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
     891                 :            :         case DNSSEC_ALGORITHM_RSASHA256:
     892                 :            :         case DNSSEC_ALGORITHM_RSASHA512:
     893                 :          8 :                 r = dnssec_rsa_verify(
     894                 :            :                                 gcry_md_algo_name(md_algorithm),
     895                 :            :                                 hash, hash_size,
     896                 :            :                                 rrsig,
     897                 :            :                                 dnskey);
     898                 :          8 :                 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                 :          8 :         case DNSSEC_ALGORITHM_ED25519:
     911                 :         16 :                 r = dnssec_eddsa_verify(
     912                 :          8 :                                 rrsig->rrsig.algorithm,
     913                 :            :                                 sig_data, sig_size,
     914                 :            :                                 rrsig,
     915                 :            :                                 dnskey);
     916                 :          8 :                 break;
     917                 :            : #endif
     918                 :            :         }
     919         [ -  + ]:         16 :         if (r < 0)
     920                 :          0 :                 return r;
     921                 :            : 
     922                 :            :         /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
     923         [ +  - ]:         16 :         if (r > 0)
     924                 :         16 :                 dnssec_fix_rrset_ttl(list, n, rrsig, realtime);
     925                 :            : 
     926         [ -  + ]:         16 :         if (r == 0)
     927                 :          0 :                 *result = DNSSEC_INVALID;
     928         [ -  + ]:         16 :         else if (wildcard)
     929                 :          0 :                 *result = DNSSEC_VALIDATED_WILDCARD;
     930                 :            :         else
     931                 :         16 :                 *result = DNSSEC_VALIDATED;
     932                 :            : 
     933                 :         16 :         return 0;
     934                 :            : }
     935                 :            : 
     936                 :         16 : int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) {
     937                 :            : 
     938         [ -  + ]:         16 :         assert(rrsig);
     939         [ -  + ]:         16 :         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         [ -  + ]:         16 :         if (rrsig->key->type != DNS_TYPE_RRSIG)
     945                 :          0 :                 return -EINVAL;
     946                 :            : 
     947         [ -  + ]:         16 :         if (dnskey->key->type != DNS_TYPE_DNSKEY)
     948                 :          0 :                 return 0;
     949         [ -  + ]:         16 :         if (dnskey->key->class != rrsig->key->class)
     950                 :          0 :                 return 0;
     951         [ -  + ]:         16 :         if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
     952                 :          0 :                 return 0;
     953   [ +  -  -  + ]:         16 :         if (!revoked_ok && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
     954                 :          0 :                 return 0;
     955         [ -  + ]:         16 :         if (dnskey->dnskey.protocol != 3)
     956                 :          0 :                 return 0;
     957         [ -  + ]:         16 :         if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
     958                 :          0 :                 return 0;
     959                 :            : 
     960         [ -  + ]:         16 :         if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag)
     961                 :          0 :                 return 0;
     962                 :            : 
     963                 :         16 :         return dns_name_equal(dns_resource_key_name(dnskey->key), rrsig->rrsig.signer);
     964                 :            : }
     965                 :            : 
     966                 :         16 : int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
     967         [ -  + ]:         16 :         assert(key);
     968         [ -  + ]:         16 :         assert(rrsig);
     969                 :            : 
     970                 :            :         /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
     971                 :            : 
     972         [ -  + ]:         16 :         if (rrsig->key->type != DNS_TYPE_RRSIG)
     973                 :          0 :                 return 0;
     974         [ -  + ]:         16 :         if (rrsig->key->class != key->class)
     975                 :          0 :                 return 0;
     976         [ -  + ]:         16 :         if (rrsig->rrsig.type_covered != key->type)
     977                 :          0 :                 return 0;
     978                 :            : 
     979                 :         16 :         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                 :          8 : static int digest_to_gcrypt_md(uint8_t algorithm) {
    1123                 :            : 
    1124                 :            :         /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
    1125                 :            : 
    1126   [ +  +  -  - ]:          8 :         switch (algorithm) {
    1127                 :            : 
    1128                 :          4 :         case DNSSEC_DIGEST_SHA1:
    1129                 :          4 :                 return GCRY_MD_SHA1;
    1130                 :            : 
    1131                 :          4 :         case DNSSEC_DIGEST_SHA256:
    1132                 :          4 :                 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                 :          8 : int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
    1143                 :            :         uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
    1144                 :          8 :         _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         [ -  + ]:          8 :         assert(dnskey);
    1150         [ -  + ]:          8 :         assert(ds);
    1151                 :            : 
    1152                 :            :         /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
    1153                 :            : 
    1154         [ -  + ]:          8 :         if (dnskey->key->type != DNS_TYPE_DNSKEY)
    1155                 :          0 :                 return -EINVAL;
    1156         [ -  + ]:          8 :         if (ds->key->type != DNS_TYPE_DS)
    1157                 :          0 :                 return -EINVAL;
    1158         [ -  + ]:          8 :         if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
    1159                 :          0 :                 return -EKEYREJECTED;
    1160   [ +  -  -  + ]:          8 :         if (!mask_revoke && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
    1161                 :          0 :                 return -EKEYREJECTED;
    1162         [ -  + ]:          8 :         if (dnskey->dnskey.protocol != 3)
    1163                 :          0 :                 return -EKEYREJECTED;
    1164                 :            : 
    1165         [ -  + ]:          8 :         if (dnskey->dnskey.algorithm != ds->ds.algorithm)
    1166                 :          0 :                 return 0;
    1167         [ -  + ]:          8 :         if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
    1168                 :          0 :                 return 0;
    1169                 :            : 
    1170                 :          8 :         initialize_libgcrypt(false);
    1171                 :            : 
    1172                 :          8 :         md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
    1173         [ -  + ]:          8 :         if (md_algorithm < 0)
    1174                 :          0 :                 return md_algorithm;
    1175                 :            : 
    1176                 :          8 :         hash_size = gcry_md_get_algo_dlen(md_algorithm);
    1177         [ -  + ]:          8 :         assert(hash_size > 0);
    1178                 :            : 
    1179         [ -  + ]:          8 :         if (ds->ds.digest_size != hash_size)
    1180                 :          0 :                 return 0;
    1181                 :            : 
    1182                 :          8 :         r = dns_name_to_wire_format(dns_resource_key_name(dnskey->key), wire_format, sizeof(wire_format), true);
    1183         [ -  + ]:          8 :         if (r < 0)
    1184                 :          0 :                 return r;
    1185                 :            : 
    1186                 :          8 :         gcry_md_open(&md, md_algorithm, 0);
    1187         [ -  + ]:          8 :         if (!md)
    1188                 :          0 :                 return -EIO;
    1189                 :            : 
    1190                 :          8 :         gcry_md_write(md, wire_format, r);
    1191         [ -  + ]:          8 :         if (mask_revoke)
    1192                 :          0 :                 md_add_uint16(md, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE);
    1193                 :            :         else
    1194                 :          8 :                 md_add_uint16(md, dnskey->dnskey.flags);
    1195                 :          8 :         md_add_uint8(md, dnskey->dnskey.protocol);
    1196                 :          8 :         md_add_uint8(md, dnskey->dnskey.algorithm);
    1197                 :          8 :         gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
    1198                 :            : 
    1199                 :          8 :         result = gcry_md_read(md, 0);
    1200         [ -  + ]:          8 :         if (!result)
    1201                 :          0 :                 return -EIO;
    1202                 :            : 
    1203                 :          8 :         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                 :          4 : 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         [ +  - ]:          4 :         switch (algorithm) {
    1249                 :            : 
    1250                 :          4 :         case NSEC3_ALGORITHM_SHA1:
    1251                 :          4 :                 return GCRY_MD_SHA1;
    1252                 :            : 
    1253                 :          0 :         default:
    1254                 :          0 :                 return -EOPNOTSUPP;
    1255                 :            :         }
    1256                 :            : }
    1257                 :            : 
    1258                 :          4 : int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
    1259                 :            :         uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
    1260                 :          4 :         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         [ -  + ]:          4 :         assert(nsec3);
    1268         [ -  + ]:          4 :         assert(name);
    1269         [ -  + ]:          4 :         assert(ret);
    1270                 :            : 
    1271         [ -  + ]:          4 :         if (nsec3->key->type != DNS_TYPE_NSEC3)
    1272                 :          0 :                 return -EINVAL;
    1273                 :            : 
    1274         [ -  + ]:          4 :         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                 :          4 :         algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm);
    1280         [ -  + ]:          4 :         if (algorithm < 0)
    1281                 :          0 :                 return algorithm;
    1282                 :            : 
    1283                 :          4 :         initialize_libgcrypt(false);
    1284                 :            : 
    1285                 :          4 :         hash_size = gcry_md_get_algo_dlen(algorithm);
    1286         [ -  + ]:          4 :         assert(hash_size > 0);
    1287                 :            : 
    1288         [ -  + ]:          4 :         if (nsec3->nsec3.next_hashed_name_size != hash_size)
    1289                 :          0 :                 return -EINVAL;
    1290                 :            : 
    1291                 :          4 :         r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
    1292         [ -  + ]:          4 :         if (r < 0)
    1293                 :          0 :                 return r;
    1294                 :            : 
    1295                 :          4 :         gcry_md_open(&md, algorithm, 0);
    1296         [ -  + ]:          4 :         if (!md)
    1297                 :          0 :                 return -EIO;
    1298                 :            : 
    1299                 :          4 :         gcry_md_write(md, wire_format, r);
    1300                 :          4 :         gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
    1301                 :            : 
    1302                 :          4 :         result = gcry_md_read(md, 0);
    1303         [ -  + ]:          4 :         if (!result) {
    1304                 :          0 :                 r = -EIO;
    1305                 :          0 :                 goto finish;
    1306                 :            :         }
    1307                 :            : 
    1308         [ +  + ]:          8 :         for (k = 0; k < nsec3->nsec3.iterations; k++) {
    1309                 :          4 :                 uint8_t tmp[hash_size];
    1310                 :          4 :                 memcpy(tmp, result, hash_size);
    1311                 :            : 
    1312                 :          4 :                 gcry_md_reset(md);
    1313                 :          4 :                 gcry_md_write(md, tmp, hash_size);
    1314                 :          4 :                 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
    1315                 :            : 
    1316                 :          4 :                 result = gcry_md_read(md, 0);
    1317         [ -  + ]:          4 :                 if (!result) {
    1318                 :          0 :                         r = -EIO;
    1319                 :          0 :                         goto finish;
    1320                 :            :                 }
    1321                 :            :         }
    1322                 :            : 
    1323                 :          4 :         memcpy(ret, result, hash_size);
    1324                 :          4 :         r = (int) hash_size;
    1325                 :            : 
    1326                 :          4 : finish:
    1327                 :          4 :         gcry_md_close(md);
    1328                 :          4 :         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   [ +  +  +  + ]:        104 : 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   [ +  +  +  + ]:         48 : DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict, DnssecVerdict);

Generated by: LCOV version 1.14