summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2014-02-23 16:20:46 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2014-02-23 16:20:46 +0000
commitd387380a250843e1790d6d3d9e2d0464afd3bf87 (patch)
tree303c67983f42c4981a324e422ef5f70aab4d7157
parentf2e4c277c49761479c9fc8ae7a7024e8a59aced2 (diff)
downloaddnsmasq-d387380a250843e1790d6d3d9e2d0464afd3bf87.tar.gz
Check signer name in RRSIGs.
-rw-r--r--src/dnssec.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/src/dnssec.c b/src/dnssec.c
index 123a3df..12d8ac3 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -682,18 +682,18 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
return STAT_INSECURE;
/* Sort RRset records into canonical order.
- Note that at this point keyname and name buffs are
+ Note that at this point keyname and daemon->workspacename buffs are
unused, and used as workspace by the sort. */
- sort_rrset(header, plen, rr_desc, rrsetidx, rrset, name, keyname);
+ sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
/* Now try all the sigs to try and find one which validates */
for (j = 0; j <sigidx; j++)
{
- unsigned char *psav, *sig;
+ unsigned char *psav, *sig, *digest;
int i, wire_len, sig_len;
const struct nettle_hash *hash;
void *ctx;
- unsigned char *digest;
+ char *name_start;
u32 nsigttl;
p = sigs[j];
@@ -710,7 +710,32 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
if (!extract_name(header, plen, &p, keyname, 1, 0))
return STAT_INSECURE;
+
+ /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
+ the name of the zone containing the RRset. We can't tell that
+ for certain, but we can check that the RRset name is equal to
+ or encloses the signers name, which should be enough to stop
+ an attacker using signatures made with the key of an unrelated
+ zone he controls. Note that the root key is always allowed. */
+ if (*keyname != 0)
+ {
+ int failed = 0;
+
+ for (name_start = name; !hostname_isequal(name_start, keyname); )
+ if ((name_start = strchr(name_start, '.')))
+ name_start++; /* chop a label off and try again */
+ else
+ {
+ failed = 1;
+ break;
+ }
+
+ /* Bad sig, try another */
+ if (failed)
+ continue;
+ }
+ /* Other 5.3.1 checks */
if (!check_date_range(sig_inception, sig_expiration) ||
labels > name_labels ||
!(hash = hash_find(algo_digest_name(algo))) ||
@@ -735,13 +760,14 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
{
int seg;
unsigned char *end, *cp;
- char *name_start = name;
u16 len, *dp;
-
+
p = rrset[i];
if (!extract_name(header, plen, &p, name, 1, 10))
return STAT_INSECURE;
+ name_start = name;
+
/* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
if (labels < name_labels)
{