/* 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
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)
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);
/* 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);
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);
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] != '*')
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)
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) {
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;
+ }
}
}
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;
}