]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/resolve/resolved-dns-dnssec.c
resolved: add missing error code check when initializing DNS-over-TLS
[thirdparty/systemd.git] / src / resolve / resolved-dns-dnssec.c
index 13da4e5991695cf9f896ae45f0e14bd5721ddb53..997cb986e610878af4a9eea3024835b9ed7eb345 100644 (file)
@@ -1,9 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <stdio_ext.h>
-
 #if HAVE_GCRYPT
-#include <gcrypt.h>
+#  include <gcrypt.h>
 #endif
 
 #include "alloc-util.h"
 #include "fileio.h"
 #include "gcrypt-util.h"
 #include "hexdecoct.h"
+#include "memory-util.h"
 #include "resolved-dns-dnssec.h"
 #include "resolved-dns-packet.h"
+#include "sort-util.h"
 #include "string-table.h"
 
 #define VERIFY_RRS_MAX 256
@@ -74,7 +74,7 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
                 return -ENOBUFS;
 
         for (;;) {
-                r = dns_label_unescape(&n, buffer, buffer_max);
+                r = dns_label_unescape(&n, buffer, buffer_max, 0);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -402,7 +402,7 @@ static int dnssec_ecdsa_verify(
         if (rrsig->rrsig.signature_size != key_size * 2)
                 return -EINVAL;
 
-        q = alloca(key_size*2 + 1);
+        q = newa(uint8_t, key_size*2 + 1);
         q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
         memcpy(q+1, dnskey->dnskey.key, key_size*2);
 
@@ -801,10 +801,9 @@ int dnssec_verify_rrset(
         /* Bring the RRs into canonical order */
         typesafe_qsort(list, n, rr_compare);
 
-        f = open_memstream(&sig_data, &sig_size);
+        f = open_memstream_unlocked(&sig_data, &sig_size);
         if (!f)
                 return -ENOMEM;
-        __fsetlocking(f, FSETLOCKING_BYCALLER);
 
         fwrite_uint16(f, rrsig->rrsig.type_covered);
         fwrite_uint8(f, rrsig->rrsig.algorithm);
@@ -1107,7 +1106,7 @@ int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
         DnsResourceRecord *rr;
         int r;
 
-        /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
+        /* Checks whether there's at least one RRSIG in 'a' that protects RRs of the specified key */
 
         DNS_ANSWER_FOREACH(rr, a) {
                 r = dnssec_key_match_rrsig(key, rr);
@@ -1705,7 +1704,7 @@ static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
                 return 0;
 
         n = dns_resource_key_name(rr->key);
-        r = dns_label_unescape(&n, label, sizeof(label));
+        r = dns_label_unescape(&n, label, sizeof label, 0);
         if (r <= 0)
                 return r;
         if (r != 1 || label[0] != '*')
@@ -1797,22 +1796,14 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
         return dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name);
 }
 
-static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) {
-        _cleanup_free_ char *wc = NULL;
-        const char *common_suffix, *signer;
-        int r;
+static int dnssec_nsec_generate_wildcard(DnsResourceRecord *rr, const char *name, char **wc) {
+        const char *common_suffix1, *common_suffix2, *signer;
+        int r, labels1, labels2;
 
         assert(rr);
         assert(rr->key->type == DNS_TYPE_NSEC);
 
-        /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
-         * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
-         * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
-         *
-         *     NSEC             bar →   waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
-         *     NSEC   waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
-         *     NSEC yyy.zzz.xoo.bar →             bar: indicates that a number of wildcards don#t exist either...
-         */
+        /* Generates "Wildcard at the Closest Encloser" for the given name and NSEC RR. */
 
         r = dns_resource_record_signer(rr, &signer);
         if (r < 0)
@@ -1822,23 +1813,31 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
         if (r <= 0)
                 return r;
 
-        r = dns_name_endswith(name, dns_resource_key_name(rr->key));
+        r = dns_name_common_suffix(name, dns_resource_key_name(rr->key), &common_suffix1);
         if (r < 0)
                 return r;
-        if (r > 0)  /* If the name we are interested in is a child of the NSEC RR, then append the asterisk to the NSEC
-                     * RR's name. */
-                r = dns_name_concat("*", dns_resource_key_name(rr->key), &wc);
-        else {
-                r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
-                if (r < 0)
-                        return r;
 
-                r = dns_name_concat("*", common_suffix, &wc);
-        }
+        r = dns_name_common_suffix(name, rr->nsec.next_domain_name, &common_suffix2);
+        if (r < 0)
+                return r;
+
+        labels1 = dns_name_count_labels(common_suffix1);
+        if (labels1 < 0)
+            return labels1;
+
+        labels2 = dns_name_count_labels(common_suffix2);
+        if (labels2 < 0)
+            return labels2;
+
+        if (labels1 > labels2)
+                r = dns_name_concat("*", common_suffix1, 0, wc);
+        else
+                r = dns_name_concat("*", common_suffix2, 0, wc);
+
         if (r < 0)
                 return r;
 
-        return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
+        return 0;
 }
 
 int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
@@ -1942,14 +1941,30 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
                         covering_rr = rr;
                         covering_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
                 }
+        }
 
-                /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
-                r = dnssec_nsec_covers_wildcard(rr, name);
+        if (covering_rr) {
+                _cleanup_free_ char *wc = NULL;
+                r = dnssec_nsec_generate_wildcard(covering_rr, name, &wc);
                 if (r < 0)
                         return r;
-                if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
-                        wildcard_rr = rr;
-                        wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
+
+                DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
+
+                        if (rr->key->class != key->class)
+                                continue;
+
+                        if (rr->key->type != DNS_TYPE_NSEC)
+                                continue;
+
+                        /* Check if this NSEC RR proves the nonexistence of the wildcard */
+                        r = dnssec_nsec_covers(rr, wc);
+                        if (r < 0)
+                                return r;
+                        if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
+                                wildcard_rr = rr;
+                                wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
+                        }
                 }
         }
 
@@ -1970,7 +1985,7 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
         if (have_nsec3)
                 return dnssec_test_nsec3(answer, key, result, authenticated, ttl);
 
-        /* No approproate NSEC RR found, report this. */
+        /* No appropriate NSEC RR found, report this. */
         *result = DNSSEC_NSEC_NO_RR;
         return 0;
 }