Commit 5ada8885 authored by Simon Kelley's avatar Simon Kelley

RFC 4035 5.3.2 wildcard label rules.

parent 5f8e58f4
...@@ -76,6 +76,21 @@ static void from_wire(char *name) ...@@ -76,6 +76,21 @@ static void from_wire(char *name)
*(l-1) = 0; *(l-1) = 0;
} }
/* Input in presentation format */
static int count_labels(char *name)
{
int i;
if (*name == 0)
return 0;
for (i = 0; *name; name++)
if (*name == '.')
i++;
return i+1;
}
/* Implement RFC1982 wrapped compare for 32-bit numbers */ /* Implement RFC1982 wrapped compare for 32-bit numbers */
static int serial_compare_32(unsigned long s1, unsigned long s2) static int serial_compare_32(unsigned long s1, unsigned long s2)
{ {
...@@ -280,7 +295,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -280,7 +295,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
static int rrset_sz = 0, sig_sz = 0; static int rrset_sz = 0, sig_sz = 0;
unsigned char *p; unsigned char *p;
int rrsetidx, sigidx, res, rdlen, j; int rrsetidx, sigidx, res, rdlen, j, name_labels;
struct crec *crecp = NULL; struct crec *crecp = NULL;
int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag; int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
u16 *rr_desc = get_desc(type); u16 *rr_desc = get_desc(type);
...@@ -288,12 +303,14 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -288,12 +303,14 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
if (!(p = skip_questions(header, plen))) if (!(p = skip_questions(header, plen)))
return STAT_INSECURE; return STAT_INSECURE;
/* look for an RRSIG record for this RRset and get pointers to each record */ name_labels = count_labels(name); /* For 4035 5.3.2 check */
/* look for RRSIGs for this RRset and get pointers to each RR in the set. */
for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount); for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
j != 0; j--) j != 0; j--)
{ {
unsigned char *pstart, *pdata; unsigned char *pstart, *pdata;
int stype, sclass, sttl; int stype, sclass;
pstart = p; pstart = p;
...@@ -302,17 +319,12 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -302,17 +319,12 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
GETSHORT(stype, p); GETSHORT(stype, p);
GETSHORT(sclass, p); GETSHORT(sclass, p);
GETLONG(sttl, p); p += 4; /* TTL */
pdata = p; pdata = p;
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
(void)sttl;
if (!CHECK_LEN(header, p, plen, rdlen))
return STAT_INSECURE; /* bad packet */
if (res == 1 && sclass == class) if (res == 1 && sclass == class)
{ {
if (stype == type) if (stype == type)
...@@ -339,24 +351,42 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -339,24 +351,42 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
if (stype == T_RRSIG) if (stype == T_RRSIG)
{ {
if (sigidx == sig_sz) if (rdlen < 18)
{ return STAT_INSECURE; /* bad packet */
unsigned char **new;
GETSHORT(type_covered, p);
/* expand */ algo = *p++;
if (!(new = whine_malloc((sig_sz + 5) * sizeof(unsigned char **)))) labels = *p++;
return STAT_INSECURE; p += 4; /* orig_ttl */
GETLONG(sig_expiration, p);
if (sigs) GETLONG(sig_inception, p);
{ p = pdata + 2; /* restore for ADD_RDLEN */
memcpy(new, sigs, sig_sz * sizeof(unsigned char **));
free(sigs); if (type_covered == type &&
} check_date_range(sig_inception, sig_expiration) &&
verifyalg_supported(algo) &&
sigs = new; labels <= name_labels)
sig_sz += 5; {
} if (sigidx == sig_sz)
sigs[sigidx++] = pdata; {
unsigned char **new;
/* expand */
if (!(new = whine_malloc((sig_sz + 5) * sizeof(unsigned char **))))
return STAT_INSECURE;
if (sigs)
{
memcpy(new, sigs, sig_sz * sizeof(unsigned char **));
free(sigs);
}
sigs = new;
sig_sz += 5;
}
sigs[sigidx++] = pdata;
}
} }
} }
...@@ -382,33 +412,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -382,33 +412,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
u32 nsigttl; u32 nsigttl;
p = sigs[j]; p = sigs[j];
GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
GETSHORT(rdlen, p);
if (rdlen < 18)
return STAT_INSECURE; /* bad packet */
psav = p; psav = p;
GETSHORT(type_covered, p); p += 2; /* type_covered - already checked */
algo = *p++; algo = *p++;
labels = *p++; labels = *p++;
GETLONG(orig_ttl, p); GETLONG(orig_ttl, p);
GETLONG(sig_expiration, p); p += 8; /* sig_expiration and sig_inception */
GETLONG(sig_inception, p);
GETSHORT(key_tag, p); GETSHORT(key_tag, p);
if (type_covered != type ||
!check_date_range(sig_inception, sig_expiration) ||
!verifyalg_supported(algo))
{
/* covers wrong type or out of date - skip */
p = psav;
if (!ADD_RDLEN(header, p, plen, rdlen))
return STAT_INSECURE;
continue;
}
if (!extract_name(header, plen, &p, keyname, 1, 0)) if (!extract_name(header, plen, &p, keyname, 1, 0))
return STAT_INSECURE; return STAT_INSECURE;
...@@ -428,24 +441,38 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -428,24 +441,38 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
digestalg_add_data(keyname, wire_len); digestalg_add_data(keyname, wire_len);
from_wire(keyname); from_wire(keyname);
/* TODO wildcard rules : 4035 5.3.2 */
for (i = 0; i < rrsetidx; ++i) for (i = 0; i < rrsetidx; ++i)
{ {
int seg; int seg;
unsigned char *end, *cp; unsigned char *end, *cp;
char *name_start = name;
u16 len, *dp; u16 len, *dp;
p = rrset[i]; p = rrset[i];
if (!extract_name(header, plen, &p, name, 1, 10)) if (!extract_name(header, plen, &p, name, 1, 10))
return STAT_INSECURE; return STAT_INSECURE;
wire_len = to_wire(name);
digestalg_add_data(name, wire_len); /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
from_wire(name); /* leave name unchanged on exit */ if (labels < name_labels)
{
int k;
for (k = name_labels - labels; k != 0; k--)
while (*name_start != '.' && *name_start != 0)
name_start++;
name_start--;
*name_start = '*';
}
wire_len = to_wire(name_start);
digestalg_add_data(name_start, wire_len);
digestalg_add_data(p, 4); /* class and type */ digestalg_add_data(p, 4); /* class and type */
digestalg_add_data(&nsigttl, 4); digestalg_add_data(&nsigttl, 4);
p += 8; /* skip class, type, ttl */ p += 8; /* skip class, type, ttl */
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return STAT_INSECURE;
end = p + rdlen; end = p + rdlen;
/* canonicalise rdata and calculate length of same, use name buffer as workspace */ /* canonicalise rdata and calculate length of same, use name buffer as workspace */
...@@ -463,13 +490,12 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in ...@@ -463,13 +490,12 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
digestalg_add_data(name, seg); digestalg_add_data(name, seg);
if (cp != end) if (cp != end)
digestalg_add_data(cp, end - cp); digestalg_add_data(cp, end - cp);
/* namebuff used for workspace, above, restore for next loop
and to leave unchanged on exit */
p = (unsigned char*)(rrset[i]);
extract_name(header, plen, &p, name, 1, 0);
} }
/* namebuff used for workspace above, restore to leave unchanged on exit */
p = (unsigned char*)(rrset[0]);
extract_name(header, plen, &p, name, 1, 0);
memcpy(alg->digest, digestalg_final(), digestalg_len()); memcpy(alg->digest, digestalg_final(), digestalg_len());
if (key) if (key)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment