summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2022-11-16 16:49:30 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2022-11-16 16:49:30 +0000
commit9ed3ee67ecd2a388d319bff116b27bcc62286ccc (patch)
tree6d85e25c0c58d99d42cb7c7714c57e447360728d
parent1f9215f5f92c5478c8aaba8054d192a5e6280e95 (diff)
downloaddnsmasq-9ed3ee67ecd2a388d319bff116b27bcc62286ccc.tar.gz
Handle DS records for unsupported crypto algorithms correctly.v2.88rc1
Such a DS, as long as it is validated, should allow answers in the domain is attests to be returned as unvalidated, and not as a validation error.
-rw-r--r--CHANGELOG7
-rw-r--r--src/crypto.c2
-rw-r--r--src/dnssec.c59
3 files changed, 44 insertions, 24 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 1090589..8d55a36 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -44,8 +44,13 @@ version 2.88
cases where is can be useful. Thanks to Dominik Derigs for
the patch.
+ Handle DS records for unsupported crypto algorithms correctly.
+ Such a DS, as long as it is validated, should allow answers
+ in the domain is attests to be returned as unvalidated, and not
+ as a validation error.
+
-(version 2.87
+version 2.87
Allow arbitrary prefix lengths in --rev-server and
--domain=....,local
diff --git a/src/crypto.c b/src/crypto.c
index d799037..2678683 100644
--- a/src/crypto.c
+++ b/src/crypto.c
@@ -452,7 +452,7 @@ char *algo_digest_name(int algo)
case 8: return "sha256"; /* RSA/SHA-256 */
case 10: return "sha512"; /* RSA/SHA-512 */
#if MIN_VERSION(3, 6)
- case 12: return "gosthash94cp"; /* ECC-GOST */
+ case 12: return "gosthash94cp"; /* ECC-GOST */
#endif
case 13: return "sha256"; /* ECDSAP256SHA256 */
case 14: return "sha384"; /* ECDSAP384SHA384 */
diff --git a/src/dnssec.c b/src/dnssec.c
index daf679e..ce01b2e 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -979,10 +979,13 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
}
/* The DNS packet is expected to contain the answer to a DS query
- Put all DSs in the answer which are valid into the cache.
+ Put all DSs in the answer which are valid and have hash and signature algos
+ we support into the cache.
Also handles replies which prove that there's no DS at this location,
either because the zone is unsigned or this isn't a zone cut. These are
cached too.
+ If none of the DS's are for supported algos, treat the answer as if
+ it's a proof of no DS at this location. RFC4035 para 5.2.
return codes:
STAT_OK At least one valid DS found and in cache.
STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
@@ -993,8 +996,8 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
{
unsigned char *p = (unsigned char *)(header+1);
- int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0;
- int aclass, atype, rdlen;
+ int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0, found_supported = 0;
+ int aclass, atype, rdlen, flags;
unsigned long ttl;
union all_addr a;
@@ -1065,14 +1068,22 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
algo = *p++;
digest = *p++;
- if ((key = blockdata_alloc((char*)p, rdlen - 4)))
+ if (!ds_digest_name(digest) || !ds_digest_name(digest))
+ {
+ a.log.keytag = keytag;
+ a.log.algo = algo;
+ a.log.digest = digest;
+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
+ neg_ttl = ttl;
+ }
+ else if ((key = blockdata_alloc((char*)p, rdlen - 4)))
{
a.ds.digest = digest;
a.ds.keydata = key;
a.ds.algo = algo;
a.ds.keytag = keytag;
a.ds.keylen = rdlen - 4;
-
+
if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
{
blockdata_free(key);
@@ -1083,26 +1094,29 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
a.log.keytag = keytag;
a.log.algo = algo;
a.log.digest = digest;
- if (ds_digest_name(digest) && algo_digest_name(algo))
- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
- else
- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
+ found_supported = 1;
}
}
p = psave;
}
+
if (!ADD_RDLEN(header, p, plen, rdlen))
return STAT_BOGUS; /* bad packet */
}
cache_end_insert();
+ /* Fall through if no supported algo DS found. */
+ if (found_supported)
+ return STAT_OK;
}
- else
+
+ flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
+
+ if (neganswer)
{
- int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
-
if (RCODE(header) == NXDOMAIN)
flags |= F_NXDOMAIN;
@@ -1110,17 +1124,18 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
to store presence/absence of NS. */
if (nons)
flags &= ~F_DNSSECOK;
-
- cache_start_insert();
-
- /* Use TTL from NSEC for negative cache entries */
- if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
- return STAT_BOGUS;
-
- cache_end_insert();
-
- log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
}
+
+ cache_start_insert();
+
+ /* Use TTL from NSEC for negative cache entries */
+ if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
+ return STAT_BOGUS;
+
+ cache_end_insert();
+
+ if (neganswer)
+ log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
return STAT_OK;
}