1 From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00 2001
2 From: Simon Kelley <simon@thekelleys.org.uk>
3 Date: Sun, 20 Dec 2015 20:44:23 +0000
4 Subject: [PATCH] More tweaks in handling unknown DNSSEC algorithms.
7 src/dnssec.c | 128 +++++++++++++++++++++++++++++-----------------------------
8 1 file changed, 63 insertions(+), 65 deletions(-)
10 diff --git a/src/dnssec.c b/src/dnssec.c
11 index 299ca64..e09f304 100644
14 @@ -70,7 +70,17 @@ static char *algo_digest_name(int algo)
20 +/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
21 +static char *nsec3_digest_name(int digest)
25 + case 1: return "sha1";
26 + default: return NULL;
30 /* Find pointer to correct hash function in nettle library */
31 static const struct nettle_hash *hash_find(char *name)
33 @@ -667,7 +677,6 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
34 static int rrset_sz = 0, sig_sz = 0;
36 int rrsetidx, sigidx, j, rdlen, res;
37 - int name_labels = count_labels(name); /* For 4035 5.3.2 check */
40 if (!(p = skip_questions(header, plen)))
41 @@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
44 unsigned char *pstart, *pdata;
45 - int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
46 + int stype, sclass, type_covered;
50 @@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
51 return 0; /* bad packet */
53 GETSHORT(type_covered, p);
56 - p += 4; /* orig_ttl */
57 - GETLONG(sig_expiration, p);
58 - GETLONG(sig_inception, p);
59 - p += 2; /* key_tag */
60 + p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
64 @@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
68 - /* Don't count signatures for algos we don't support */
69 - if (check_date_range(sig_inception, sig_expiration) &&
70 - labels <= name_labels &&
71 - type_covered == type &&
74 + if (type_covered == type)
76 if (!expand_workspace(&sigs, &sig_sz, sigidx))
78 @@ -795,7 +796,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
79 char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
82 - int rdlen, j, name_labels;
83 + int rdlen, j, name_labels, sig_expiration, sig_inception;
84 struct crec *crecp = NULL;
85 int algo, labels, orig_ttl, key_tag;
86 u16 *rr_desc = rrfilter_desc(type);
87 @@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
91 - p += 8; /* sig_expiration, sig_inception already checked */
92 + GETLONG(sig_expiration, p);
93 + GETLONG(sig_inception, p);
96 if (!extract_name(header, plen, &p, keyname, 1, 0))
99 - if (!(hash = hash_find(algo_digest_name(algo))) ||
100 + if (!check_date_range(sig_inception, sig_expiration) ||
101 + labels > name_labels ||
102 + !(hash = hash_find(algo_digest_name(algo))) ||
103 !hash_init(hash, &ctx, &digest))
106 @@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
109 a.addr.keytag = keytag;
110 - log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
111 + if (verify_func(algo))
112 + log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
114 + log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)");
116 recp1->addr.key.keylen = rdlen - 4;
117 recp1->addr.key.keydata = key;
118 @@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
121 a.addr.keytag = keytag;
122 - log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
123 + if (hash_find(ds_digest_name(digest)) && verify_func(algo))
124 + log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
126 + log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (not supported)");
128 crecp->addr.ds.digest = digest;
129 crecp->addr.ds.keydata = key;
130 crecp->addr.ds.algo = algo;
131 @@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
134 /* Look though the NSEC3 records to find the first one with
135 - an algorithm we support (currently only algo == 1).
136 + an algorithm we support.
138 Take the algo, iterations, and salt of that record
139 as the ones we're going to use, and prune any
140 @@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
141 p += 10; /* type, class, TTL, rdlen */
145 + if ((hash = hash_find(nsec3_digest_name(algo))))
146 break; /* known algo */
149 @@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
153 - /* Algo is checked as 1 above */
154 - if (!(hash = hash_find("sha1")))
157 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
160 @@ -1843,8 +1850,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
162 if (type_found == T_NSEC)
163 return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
165 + else if (type_found == T_NSEC3)
166 return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
171 /* Check signing status of name.
172 @@ -1857,7 +1866,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
174 static int zone_status(char *name, int class, char *keyname, time_t now)
176 - int secure_ds, name_start = strlen(name);
177 + int name_start = strlen(name);
181 @@ -1867,51 +1876,40 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
183 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
186 + /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
187 + F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
188 + but that's because there's no NS record either, ie this isn't the start
189 + of a zone. We only prove that the DNS tree below a node is unsigned when
190 + we prove that we're at a zone cut AND there's no DS record. */
191 + if (crecp->flags & F_NEG)
193 + if (crecp->flags & F_DNSSECOK)
194 + return STAT_INSECURE; /* proved no DS here */
202 + /* If all the DS records have digest and/or sig algos we don't support,
203 + then the zone is insecure. Note that if an algo
204 + appears in the DS, then RRSIGs for that algo MUST
205 + exist for each RRset: 4035 para 2.2 So if we find
206 + a DS here with digest and sig we can do, we're entitled
207 + to assume we can validate the zone and if we can't later,
208 + because an RRSIG is missing we return BOGUS.
212 - if (crecp->uid == (unsigned int)class)
214 - /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
215 - F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
216 - but that's because there's no NS record either, ie this isn't the start
217 - of a zone. We only prove that the DNS tree below a node is unsigned when
218 - we prove that we're at a zone cut AND there's no DS record.
220 - if (crecp->flags & F_NEG)
222 - if (crecp->flags & F_DNSSECOK)
223 - return STAT_INSECURE; /* proved no DS here */
225 - else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
226 - return STAT_INSECURE; /* algo we can't use - insecure */
230 + if (crecp->uid == (unsigned int)class &&
231 + hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
232 + verify_func(crecp->addr.ds.algo))
235 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
240 - /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
241 - that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
242 - one we can use. However the DNSKEY RRset may contain more than one key and
243 - one of the other keys may use an algorithm we don't support. If that's
244 - the case the zone is insecure for us. */
246 - if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
247 - return STAT_NEED_KEY;
251 - if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
252 - return STAT_INSECURE;
254 - while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
256 + return STAT_INSECURE;