]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
bird: New package
[ipfire-2.x.git] / src / patches / dnsmasq / 026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
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.
5
6 ---
7 src/dnssec.c | 128 +++++++++++++++++++++++++++++-----------------------------
8 1 file changed, 63 insertions(+), 65 deletions(-)
9
10 diff --git a/src/dnssec.c b/src/dnssec.c
11 index 299ca64..e09f304 100644
12 --- a/src/dnssec.c
13 +++ b/src/dnssec.c
14 @@ -70,7 +70,17 @@ static char *algo_digest_name(int algo)
15 default: return NULL;
16 }
17 }
18 -
19 +
20 +/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
21 +static char *nsec3_digest_name(int digest)
22 +{
23 + switch (digest)
24 + {
25 + case 1: return "sha1";
26 + default: return NULL;
27 + }
28 +}
29 +
30 /* Find pointer to correct hash function in nettle library */
31 static const struct nettle_hash *hash_find(char *name)
32 {
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;
35 unsigned char *p;
36 int rrsetidx, sigidx, j, rdlen, res;
37 - int name_labels = count_labels(name); /* For 4035 5.3.2 check */
38 int gotkey = 0;
39
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
42 j != 0; j--)
43 {
44 unsigned char *pstart, *pdata;
45 - int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
46 + int stype, sclass, type_covered;
47
48 pstart = p;
49
50 @@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
51 return 0; /* bad packet */
52
53 GETSHORT(type_covered, p);
54 - algo = *p++;
55 - labels = *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 */
61
62 if (gotkey)
63 {
64 @@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
65 }
66 }
67
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 &&
72 - verify_func(algo))
73 +
74 + if (type_covered == type)
75 {
76 if (!expand_workspace(&sigs, &sig_sz, sigidx))
77 return 0;
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)
80 {
81 unsigned char *p;
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
88 algo = *p++;
89 labels = *p++;
90 GETLONG(orig_ttl, p);
91 - p += 8; /* sig_expiration, sig_inception already checked */
92 + GETLONG(sig_expiration, p);
93 + GETLONG(sig_inception, p);
94 GETSHORT(key_tag, p);
95
96 if (!extract_name(header, plen, &p, keyname, 1, 0))
97 return STAT_BOGUS;
98
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))
104 continue;
105
106 @@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
107 else
108 {
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");
113 + else
114 + log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)");
115
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
119 else
120 {
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");
125 + else
126 + log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (not supported)");
127 +
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
132 *nons = 1;
133
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.
137
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 */
142 algo = *p++;
143
144 - if (algo == 1)
145 + if ((hash = hash_find(nsec3_digest_name(algo))))
146 break; /* known algo */
147 }
148
149 @@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
150 nsecs[i] = nsec3p;
151 }
152
153 - /* Algo is checked as 1 above */
154 - if (!(hash = hash_find("sha1")))
155 - return 0;
156 -
157 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
158 return 0;
159
160 @@ -1843,8 +1850,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
161
162 if (type_found == T_NSEC)
163 return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
164 - else
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);
167 + else
168 + return 0;
169 }
170
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
173 */
174 static int zone_status(char *name, int class, char *keyname, time_t now)
175 {
176 - int secure_ds, name_start = strlen(name);
177 + int name_start = strlen(name);
178 struct crec *crecp;
179 char *p;
180
181 @@ -1867,51 +1876,40 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
182
183 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
184 return STAT_NEED_DS;
185 +
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)
192 + {
193 + if (crecp->flags & F_DNSSECOK)
194 + return STAT_INSECURE; /* proved no DS here */
195 + }
196 else
197 {
198 - secure_ds = 0;
199 -
200 + int gotone = 0;
201 +
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.
209 + */
210 do
211 {
212 - if (crecp->uid == (unsigned int)class)
213 - {
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.
219 - */
220 - if (crecp->flags & F_NEG)
221 - {
222 - if (crecp->flags & F_DNSSECOK)
223 - return STAT_INSECURE; /* proved no DS here */
224 - }
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 */
227 - else
228 - secure_ds = 1;
229 - }
230 + if (crecp->uid == (unsigned int)class &&
231 + hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
232 + verify_func(crecp->addr.ds.algo))
233 + gotone = 1;
234 }
235 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
236 - }
237 -
238 - if (secure_ds)
239 - {
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. */
245 -
246 - if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
247 - return STAT_NEED_KEY;
248
249 - do
250 - {
251 - if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
252 - return STAT_INSECURE;
253 - }
254 - while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
255 + if (!gotone)
256 + return STAT_INSECURE;
257 }
258
259 if (name_start == 0)
260 --
261 1.7.10.4
262