blob: 4d64cccadb49a40358649a7782d7f5c8b961e5c5 [file] [log] [blame]
Giovanni Bajo8d41ebd2012-05-05 00:48:12 +02001/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00002 and Copyright (c) 2012-2018 Simon Kelley
Giovanni Bajo8d41ebd2012-05-05 00:48:12 +02003
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 dated June, 1991, or
7 (at your option) version 3 dated 29 June, 2007.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
Giovanni Bajoe292e932012-04-22 14:32:02 +020017
18#include "dnsmasq.h"
Simon Kelley0fc2f312014-01-08 10:26:58 +000019
20#ifdef HAVE_DNSSEC
21
Giovanni Bajoe292e932012-04-22 14:32:02 +020022#define SERIAL_UNDEF -100
23#define SERIAL_EQ 0
24#define SERIAL_LT -1
25#define SERIAL_GT 1
26
Simon Kelley0fc2f312014-01-08 10:26:58 +000027/* Convert from presentation format to wire format, in place.
28 Also map UC -> LC.
29 Note that using extract_name to get presentation format
30 then calling to_wire() removes compression and maps case,
31 thus generating names in canonical form.
32 Calling to_wire followed by from_wire is almost an identity,
33 except that the UC remains mapped to LC.
Simon Kelleycbe379a2015-04-21 22:57:06 +010034
35 Note that both /000 and '.' are allowed within labels. These get
36 represented in presentation format using NAME_ESCAPE as an escape
37 character. In theory, if all the characters in a name were /000 or
38 '.' or NAME_ESCAPE then all would have to be escaped, so the
39 presentation format would be twice as long as the spec (1024).
Josh Soref730c6742017-02-06 16:14:04 +000040 The buffers are all declared as 2049 (allowing for the trailing zero)
Simon Kelleycbe379a2015-04-21 22:57:06 +010041 for this reason.
Simon Kelley0fc2f312014-01-08 10:26:58 +000042*/
43static int to_wire(char *name)
Giovanni Bajo7f0485c2012-04-28 12:59:49 +020044{
Simon Kelleycbe379a2015-04-21 22:57:06 +010045 unsigned char *l, *p, *q, term;
Simon Kelley0fc2f312014-01-08 10:26:58 +000046 int len;
47
48 for (l = (unsigned char*)name; *l != 0; l = p)
49 {
50 for (p = l; *p != '.' && *p != 0; p++)
51 if (*p >= 'A' && *p <= 'Z')
52 *p = *p - 'A' + 'a';
Simon Kelleycbe379a2015-04-21 22:57:06 +010053 else if (*p == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +010054 {
55 for (q = p; *q; q++)
Simon Kelleycbe379a2015-04-21 22:57:06 +010056 *q = *(q+1);
Simon Kelleyb8f16552015-04-22 21:14:31 +010057 (*p)--;
58 }
Simon Kelley0fc2f312014-01-08 10:26:58 +000059 term = *p;
60
61 if ((len = p - l) != 0)
62 memmove(l+1, l, len);
63 *l = len;
64
65 p++;
66
67 if (term == 0)
68 *p = 0;
69 }
70
71 return l + 1 - (unsigned char *)name;
Giovanni Bajo7f0485c2012-04-28 12:59:49 +020072}
73
Simon Kelley0fc2f312014-01-08 10:26:58 +000074/* Note: no compression allowed in input. */
75static void from_wire(char *name)
Giovanni Bajo13e435e2012-04-27 03:19:40 +020076{
Simon Kelleycbe379a2015-04-21 22:57:06 +010077 unsigned char *l, *p, *last;
Simon Kelley0fc2f312014-01-08 10:26:58 +000078 int len;
Simon Kelleycbe379a2015-04-21 22:57:06 +010079
80 for (last = (unsigned char *)name; *last != 0; last += *last+1);
81
Simon Kelley0fc2f312014-01-08 10:26:58 +000082 for (l = (unsigned char *)name; *l != 0; l += len+1)
Giovanni Bajo13e435e2012-04-27 03:19:40 +020083 {
Simon Kelley0fc2f312014-01-08 10:26:58 +000084 len = *l;
85 memmove(l, l+1, len);
Simon Kelleycbe379a2015-04-21 22:57:06 +010086 for (p = l; p < l + len; p++)
87 if (*p == '.' || *p == 0 || *p == NAME_ESCAPE)
88 {
89 memmove(p+1, p, 1 + last - p);
90 len++;
Simon Kelleyb8f16552015-04-22 21:14:31 +010091 *p++ = NAME_ESCAPE;
92 (*p)++;
Simon Kelleycbe379a2015-04-21 22:57:06 +010093 }
94
Simon Kelley0fc2f312014-01-08 10:26:58 +000095 l[len] = '.';
Giovanni Bajo13e435e2012-04-27 03:19:40 +020096 }
Giovanni Bajo7f0485c2012-04-28 12:59:49 +020097
Simon Kelleye3f14552014-03-01 17:58:28 +000098 if ((char *)l != name)
Simon Kelleybd9b3cf2014-03-01 16:12:28 +000099 *(l-1) = 0;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200100}
101
Simon Kelley5ada8882014-01-09 22:25:03 +0000102/* Input in presentation format */
103static int count_labels(char *name)
104{
105 int i;
Simon Kelley4fe67442018-01-19 12:26:08 +0000106 char *p;
107
Simon Kelley5ada8882014-01-09 22:25:03 +0000108 if (*name == 0)
109 return 0;
110
Simon Kelley4fe67442018-01-19 12:26:08 +0000111 for (p = name, i = 0; *p; p++)
112 if (*p == '.')
Simon Kelley5ada8882014-01-09 22:25:03 +0000113 i++;
114
Simon Kelley4fe67442018-01-19 12:26:08 +0000115 /* Don't count empty first label. */
116 return *name == '.' ? i : i+1;
Simon Kelley5ada8882014-01-09 22:25:03 +0000117}
118
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000119/* Implement RFC1982 wrapped compare for 32-bit numbers */
Simon Kelleycc7cb0b2016-01-04 16:04:51 +0000120static int serial_compare_32(u32 s1, u32 s2)
Giovanni Bajo0852d762012-04-28 03:49:24 +0200121{
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000122 if (s1 == s2)
123 return SERIAL_EQ;
Giovanni Bajo0852d762012-04-28 03:49:24 +0200124
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000125 if ((s1 < s2 && (s2 - s1) < (1UL<<31)) ||
126 (s1 > s2 && (s1 - s2) > (1UL<<31)))
127 return SERIAL_LT;
128 if ((s1 < s2 && (s2 - s1) > (1UL<<31)) ||
129 (s1 > s2 && (s1 - s2) < (1UL<<31)))
130 return SERIAL_GT;
131 return SERIAL_UNDEF;
132}
Giovanni Bajo0852d762012-04-28 03:49:24 +0200133
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000134/* Called at startup. If the timestamp file is configured and exists, put its mtime on
135 timestamp_time. If it doesn't exist, create it, and set the mtime to 1-1-2015.
Simon Kelley360f2512015-03-07 18:28:06 +0000136 return -1 -> Cannot create file.
137 0 -> not using timestamp, or timestamp exists and is in past.
138 1 -> timestamp exists and is in future.
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000139*/
Simon Kelley360f2512015-03-07 18:28:06 +0000140
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000141static time_t timestamp_time;
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000142
Simon Kelley360f2512015-03-07 18:28:06 +0000143int setup_timestamp(void)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000144{
145 struct stat statbuf;
146
Kevin Darbyshire-Bryant34b5d192015-07-27 19:34:23 +0100147 daemon->back_to_the_future = 0;
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000148
Simon Kelley360f2512015-03-07 18:28:06 +0000149 if (!daemon->timestamp_file)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000150 return 0;
151
152 if (stat(daemon->timestamp_file, &statbuf) != -1)
153 {
154 timestamp_time = statbuf.st_mtime;
155 check_and_exit:
156 if (difftime(timestamp_time, time(0)) <= 0)
157 {
158 /* time already OK, update timestamp, and do key checking from the start. */
Vladislav Grishenko4583dd92017-05-03 23:16:51 +0100159 if (utimes(daemon->timestamp_file, NULL) == -1)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000160 my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
Kevin Darbyshire-Bryant34b5d192015-07-27 19:34:23 +0100161 daemon->back_to_the_future = 1;
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000162 return 0;
163 }
164 return 1;
165 }
166
167 if (errno == ENOENT)
168 {
Simon Kelley360f2512015-03-07 18:28:06 +0000169 /* NB. for explanation of O_EXCL flag, see comment on pidfile in dnsmasq.c */
170 int fd = open(daemon->timestamp_file, O_WRONLY | O_CREAT | O_NONBLOCK | O_EXCL, 0666);
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000171 if (fd != -1)
172 {
Vladislav Grishenko4583dd92017-05-03 23:16:51 +0100173 struct timeval tv[2];
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000174
175 close(fd);
176
Vladislav Grishenko4583dd92017-05-03 23:16:51 +0100177 timestamp_time = 1420070400; /* 1-1-2015 */
178 tv[0].tv_sec = tv[1].tv_sec = timestamp_time;
179 tv[0].tv_usec = tv[1].tv_usec = 0;
180 if (utimes(daemon->timestamp_file, tv) == 0)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000181 goto check_and_exit;
182 }
183 }
184
Simon Kelley360f2512015-03-07 18:28:06 +0000185 return -1;
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000186}
187
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000188/* Check whether today/now is between date_start and date_end */
Simon Kelleycc7cb0b2016-01-04 16:04:51 +0000189static int check_date_range(u32 date_start, u32 date_end)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000190{
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000191 unsigned long curtime = time(0);
192
Simon Kelleye98bd522014-03-28 20:41:23 +0000193 /* Checking timestamps may be temporarily disabled */
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000194
195 /* If the current time if _before_ the timestamp
196 on our persistent timestamp file, then assume the
197 time if not yet correct, and don't check the
198 key timestamps. As soon as the current time is
199 later then the timestamp, update the timestamp
200 and start checking keys */
201 if (daemon->timestamp_file)
202 {
Kevin Darbyshire-Bryant34b5d192015-07-27 19:34:23 +0100203 if (daemon->back_to_the_future == 0 && difftime(timestamp_time, curtime) <= 0)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000204 {
Vladislav Grishenko4583dd92017-05-03 23:16:51 +0100205 if (utimes(daemon->timestamp_file, NULL) != 0)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000206 my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
207
Kevin Darbyshire-Bryant06093a92016-07-11 21:03:27 +0100208 my_syslog(LOG_INFO, _("system time considered valid, now checking DNSSEC signature timestamps."));
Kevin Darbyshire-Bryant34b5d192015-07-27 19:34:23 +0100209 daemon->back_to_the_future = 1;
Kevin Darbyshire-Bryant06093a92016-07-11 21:03:27 +0100210 daemon->dnssec_no_time_check = 0;
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000211 queue_event(EVENT_RELOAD); /* purge cache */
212 }
213
Kevin Darbyshire-Bryant34b5d192015-07-27 19:34:23 +0100214 if (daemon->back_to_the_future == 0)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000215 return 1;
216 }
Kevin Darbyshire-Bryant06093a92016-07-11 21:03:27 +0100217 else if (daemon->dnssec_no_time_check)
Simon Kelleye98bd522014-03-28 20:41:23 +0000218 return 1;
219
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000220 /* We must explicitly check against wanted values, because of SERIAL_UNDEF */
221 return serial_compare_32(curtime, date_start) == SERIAL_GT
222 && serial_compare_32(curtime, date_end) == SERIAL_LT;
223}
224
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000225/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
226 data, pointed to by *p, should be used raw. */
Simon Kelley094b5c32014-12-21 16:11:52 +0000227static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000228 unsigned char **p, u16 **desc)
229{
230 int d = **desc;
231
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000232 /* No more data needs mangling */
233 if (d == (u16)-1)
Simon Kelley094b5c32014-12-21 16:11:52 +0000234 {
235 /* If there's more data than we have space for, just return what fits,
236 we'll get called again for more chunks */
237 if (end - *p > bufflen)
238 {
239 memcpy(buff, *p, bufflen);
240 *p += bufflen;
241 return bufflen;
242 }
243
244 return 0;
245 }
246
247 (*desc)++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000248
Simon Kelley394ff492015-03-29 22:17:14 +0100249 if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000250 /* domain-name, canonicalise */
251 return to_wire(buff);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000252 else
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000253 {
254 /* plain data preceding a domain-name, don't run off the end of the data */
255 if ((end - *p) < d)
256 d = end - *p;
257
258 if (d != 0)
259 {
260 memcpy(buff, *p, d);
261 *p += d;
262 }
263
264 return d;
265 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000266}
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000267
268/* Bubble sort the RRset into the canonical order.
269 Note that the byte-streams from two RRs may get unsynced: consider
270 RRs which have two domain-names at the start and then other data.
271 The domain-names may have different lengths in each RR, but sort equal
272
273 ------------
274 |abcde|fghi|
275 ------------
276 |abcd|efghi|
277 ------------
278
279 leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
280*/
281
Simon Kelleye5412452018-01-06 22:16:31 +0000282static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
283 unsigned char **rrset, char *buff1, char *buff2)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000284{
Simon Kelleye5412452018-01-06 22:16:31 +0000285 int swap, quit, i, j;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000286
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000287 do
288 {
289 for (swap = 0, i = 0; i < rrsetidx-1; i++)
290 {
291 int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
292 u16 *dp1, *dp2;
293 unsigned char *end1, *end2;
Simon Kelley5107ace2014-02-23 10:48:32 +0000294 /* Note that these have been determined to be OK previously,
295 so we don't need to check for NULL return here. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000296 unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
297 unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
298
299 p1 += 8; /* skip class, type, ttl */
300 GETSHORT(rdlen1, p1);
301 end1 = p1 + rdlen1;
302
303 p2 += 8; /* skip class, type, ttl */
304 GETSHORT(rdlen2, p2);
305 end2 = p2 + rdlen2;
306
307 dp1 = dp2 = rr_desc;
308
Simon Kelley1486a9c2014-01-10 11:39:14 +0000309 for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000310 {
Simon Kelley1486a9c2014-01-10 11:39:14 +0000311 if (left1 != 0)
312 memmove(buff1, buff1 + len1 - left1, left1);
313
Simon Kelleycbe379a2015-04-21 22:57:06 +0100314 if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000315 {
316 quit = 1;
317 len1 = end1 - p1;
318 memcpy(buff1 + left1, p1, len1);
319 }
320 len1 += left1;
321
Simon Kelley1486a9c2014-01-10 11:39:14 +0000322 if (left2 != 0)
323 memmove(buff2, buff2 + len2 - left2, left2);
324
Simon Kelleycbe379a2015-04-21 22:57:06 +0100325 if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000326 {
327 quit = 1;
328 len2 = end2 - p2;
329 memcpy(buff2 + left2, p2, len2);
330 }
331 len2 += left2;
332
333 if (len1 > len2)
Simon Kelley1486a9c2014-01-10 11:39:14 +0000334 left1 = len1 - len2, left2 = 0, len = len2;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000335 else
Simon Kelley1486a9c2014-01-10 11:39:14 +0000336 left2 = len2 - len1, left1 = 0, len = len1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000337
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000338 rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000339
Simon Kelley4619d942014-01-16 19:53:06 +0000340 if (rc > 0 || (rc == 0 && quit && len1 > len2))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000341 {
342 unsigned char *tmp = rrset[i+1];
343 rrset[i+1] = rrset[i];
344 rrset[i] = tmp;
345 swap = quit = 1;
346 }
Simon Kelleye5412452018-01-06 22:16:31 +0000347 else if (rc == 0 && quit && len1 == len2)
348 {
349 /* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
350 for (j = i+1; j < rrsetidx-1; j++)
351 rrset[j] = rrset[j+1];
352 rrsetidx--;
353 i--;
354 }
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000355 else if (rc < 0)
356 quit = 1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000357 }
358 }
359 } while (swap);
Simon Kelleye5412452018-01-06 22:16:31 +0000360
361 return rrsetidx;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000362}
363
Simon Kelley9a31b682015-12-15 10:20:39 +0000364static unsigned char **rrset = NULL, **sigs = NULL;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000365
Josh Soref730c6742017-02-06 16:14:04 +0000366/* Get pointers to RRset members and signature(s) for same.
Simon Kelley9a31b682015-12-15 10:20:39 +0000367 Check signatures, and return keyname associated in keyname. */
368static int explore_rrset(struct dns_header *header, size_t plen, int class, int type,
369 char *name, char *keyname, int *sigcnt, int *rrcnt)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000370{
Simon Kelley9a31b682015-12-15 10:20:39 +0000371 static int rrset_sz = 0, sig_sz = 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000372 unsigned char *p;
Simon Kelley9a31b682015-12-15 10:20:39 +0000373 int rrsetidx, sigidx, j, rdlen, res;
Simon Kelley9a31b682015-12-15 10:20:39 +0000374 int gotkey = 0;
375
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000376 if (!(p = skip_questions(header, plen)))
Simon Kelley05299fd2019-07-15 22:04:20 +0100377 return 0;
Simon Kelley5ada8882014-01-09 22:25:03 +0000378
Simon Kelley9a31b682015-12-15 10:20:39 +0000379 /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000380 for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
381 j != 0; j--)
382 {
383 unsigned char *pstart, *pdata;
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000384 int stype, sclass, type_covered;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000385
386 pstart = p;
387
388 if (!(res = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley05299fd2019-07-15 22:04:20 +0100389 return 0; /* bad packet */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000390
391 GETSHORT(stype, p);
392 GETSHORT(sclass, p);
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000393 p += 4; /* TTL */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000394
395 pdata = p;
396
397 GETSHORT(rdlen, p);
398
Simon Kelleye7829ae2014-01-22 22:21:51 +0000399 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley9a31b682015-12-15 10:20:39 +0000400 return 0;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000401
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000402 if (res == 1 && sclass == class)
403 {
404 if (stype == type)
405 {
Simon Kelley613ad152014-02-25 23:02:28 +0000406 if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
Simon Kelley9a31b682015-12-15 10:20:39 +0000407 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +0000408
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000409 rrset[rrsetidx++] = pstart;
410 }
411
412 if (stype == T_RRSIG)
413 {
Simon Kelley613ad152014-02-25 23:02:28 +0000414 if (rdlen < 18)
Simon Kelley9a31b682015-12-15 10:20:39 +0000415 return 0; /* bad packet */
Simon Kelley613ad152014-02-25 23:02:28 +0000416
417 GETSHORT(type_covered, p);
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000418 p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
Simon Kelley613ad152014-02-25 23:02:28 +0000419
Simon Kelley9a31b682015-12-15 10:20:39 +0000420 if (gotkey)
421 {
422 /* If there's more than one SIG, ensure they all have same keyname */
423 if (extract_name(header, plen, &p, keyname, 0, 0) != 1)
424 return 0;
425 }
426 else
427 {
428 gotkey = 1;
429
430 if (!extract_name(header, plen, &p, keyname, 1, 0))
431 return 0;
432
433 /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
434 the name of the zone containing the RRset. We can't tell that
435 for certain, but we can check that the RRset name is equal to
436 or encloses the signers name, which should be enough to stop
437 an attacker using signatures made with the key of an unrelated
438 zone he controls. Note that the root key is always allowed. */
439 if (*keyname != 0)
440 {
441 char *name_start;
442 for (name_start = name; !hostname_isequal(name_start, keyname); )
443 if ((name_start = strchr(name_start, '.')))
444 name_start++; /* chop a label off and try again */
445 else
446 return 0;
447 }
448 }
449
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000450
451 if (type_covered == type)
Simon Kelley613ad152014-02-25 23:02:28 +0000452 {
453 if (!expand_workspace(&sigs, &sig_sz, sigidx))
Simon Kelley9a31b682015-12-15 10:20:39 +0000454 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +0000455
456 sigs[sigidx++] = pdata;
457 }
458
459 p = pdata + 2; /* restore for ADD_RDLEN */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000460 }
461 }
Simon Kelley613ad152014-02-25 23:02:28 +0000462
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000463 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley9a31b682015-12-15 10:20:39 +0000464 return 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000465 }
466
Simon Kelley9a31b682015-12-15 10:20:39 +0000467 *sigcnt = sigidx;
468 *rrcnt = rrsetidx;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000469
Simon Kelley9a31b682015-12-15 10:20:39 +0000470 return 1;
471}
472
473/* Validate a single RRset (class, type, name) in the supplied DNS reply
474 Return code:
475 STAT_SECURE if it validates.
476 STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
477 (In this case *wildcard_out points to the "body" of the wildcard within name.)
478 STAT_BOGUS signature is wrong, bad packet.
479 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
480 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
481
Simon Kelley2dbba342015-12-16 13:41:58 +0000482 If key is non-NULL, use that key, which has the algo and tag given in the params of those names,
Simon Kelley9a31b682015-12-15 10:20:39 +0000483 otherwise find the key in the cache.
484
Simon Kelley2dbba342015-12-16 13:41:58 +0000485 Name is unchanged on exit. keyname is used as workspace and trashed.
Simon Kelley9a31b682015-12-15 10:20:39 +0000486
487 Call explore_rrset first to find and count RRs and sigs.
488*/
489static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, int sigidx, int rrsetidx,
490 char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
491{
492 unsigned char *p;
Simon Kelleycc7cb0b2016-01-04 16:04:51 +0000493 int rdlen, j, name_labels, algo, labels, orig_ttl, key_tag;
Simon Kelley9a31b682015-12-15 10:20:39 +0000494 struct crec *crecp = NULL;
Simon Kelleyc2bcd1e2015-12-15 17:25:21 +0000495 u16 *rr_desc = rrfilter_desc(type);
Simon Kelleycc7cb0b2016-01-04 16:04:51 +0000496 u32 sig_expiration, sig_inception
497;
Simon Kelley9a31b682015-12-15 10:20:39 +0000498 if (wildcard_out)
499 *wildcard_out = NULL;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000500
Simon Kelley9a31b682015-12-15 10:20:39 +0000501 name_labels = count_labels(name); /* For 4035 5.3.2 check */
502
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000503 /* Sort RRset records into canonical order.
Simon Kelleyd3873802014-02-23 16:20:46 +0000504 Note that at this point keyname and daemon->workspacename buffs are
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000505 unused, and used as workspace by the sort. */
Simon Kelleye5412452018-01-06 22:16:31 +0000506 rrsetidx = sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000507
508 /* Now try all the sigs to try and find one which validates */
509 for (j = 0; j <sigidx; j++)
510 {
Simon Kelleyd3873802014-02-23 16:20:46 +0000511 unsigned char *psav, *sig, *digest;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000512 int i, wire_len, sig_len;
513 const struct nettle_hash *hash;
514 void *ctx;
Simon Kelleyd3873802014-02-23 16:20:46 +0000515 char *name_start;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000516 u32 nsigttl;
517
518 p = sigs[j];
Simon Kelley5ada8882014-01-09 22:25:03 +0000519 GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000520 psav = p;
521
Simon Kelley5ada8882014-01-09 22:25:03 +0000522 p += 2; /* type_covered - already checked */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000523 algo = *p++;
524 labels = *p++;
525 GETLONG(orig_ttl, p);
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000526 GETLONG(sig_expiration, p);
527 GETLONG(sig_inception, p);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000528 GETSHORT(key_tag, p);
529
Simon Kelley394ff492015-03-29 22:17:14 +0100530 if (!extract_name(header, plen, &p, keyname, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +0000531 return STAT_BOGUS;
Simon Kelleyd3873802014-02-23 16:20:46 +0000532
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000533 if (!check_date_range(sig_inception, sig_expiration) ||
534 labels > name_labels ||
535 !(hash = hash_find(algo_digest_name(algo))) ||
Simon Kelleye7829ae2014-01-22 22:21:51 +0000536 !hash_init(hash, &ctx, &digest))
537 continue;
Simon Kelley9a31b682015-12-15 10:20:39 +0000538
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000539 /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
540 if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
541 return STAT_NEED_KEY;
542
Simon Kelley86bec2d2014-01-13 21:31:20 +0000543 sig = p;
544 sig_len = rdlen - (p - psav);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000545
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000546 nsigttl = htonl(orig_ttl);
547
Simon Kelley86bec2d2014-01-13 21:31:20 +0000548 hash->update(ctx, 18, psav);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000549 wire_len = to_wire(keyname);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000550 hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000551 from_wire(keyname);
552
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000553 for (i = 0; i < rrsetidx; ++i)
554 {
555 int seg;
556 unsigned char *end, *cp;
557 u16 len, *dp;
Simon Kelleyd3873802014-02-23 16:20:46 +0000558
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000559 p = rrset[i];
Simon Kelleye5412452018-01-06 22:16:31 +0000560
Simon Kelley394ff492015-03-29 22:17:14 +0100561 if (!extract_name(header, plen, &p, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +0000562 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000563
Simon Kelleyd3873802014-02-23 16:20:46 +0000564 name_start = name;
565
Simon Kelley5ada8882014-01-09 22:25:03 +0000566 /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
567 if (labels < name_labels)
568 {
569 int k;
570 for (k = name_labels - labels; k != 0; k--)
Simon Kelleyfbc52052014-12-23 15:46:08 +0000571 {
572 while (*name_start != '.' && *name_start != 0)
573 name_start++;
Simon Kelley0b1008d2014-12-27 15:33:32 +0000574 if (k != 1 && *name_start == '.')
Simon Kelleyfbc52052014-12-23 15:46:08 +0000575 name_start++;
576 }
577
578 if (wildcard_out)
579 *wildcard_out = name_start+1;
580
Simon Kelley5ada8882014-01-09 22:25:03 +0000581 name_start--;
582 *name_start = '*';
583 }
584
585 wire_len = to_wire(name_start);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000586 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
587 hash->update(ctx, 4, p); /* class and type */
588 hash->update(ctx, 4, (unsigned char *)&nsigttl);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000589
590 p += 8; /* skip class, type, ttl */
591 GETSHORT(rdlen, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000592 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000593 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000594
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000595 end = p + rdlen;
596
Simon Kelleycbe379a2015-04-21 22:57:06 +0100597 /* canonicalise rdata and calculate length of same, use name buffer as workspace.
598 Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000599 cp = p;
600 dp = rr_desc;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100601 for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000602 len += end - cp;
603 len = htons(len);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000604 hash->update(ctx, 2, (unsigned char *)&len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000605
606 /* Now canonicalise again and digest. */
607 cp = p;
608 dp = rr_desc;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100609 while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000610 hash->update(ctx, seg, (unsigned char *)name);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000611 if (cp != end)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000612 hash->update(ctx, end - cp, cp);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000613 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000614
615 hash->digest(ctx, hash->digest_size, digest);
616
Simon Kelley5ada8882014-01-09 22:25:03 +0000617 /* namebuff used for workspace above, restore to leave unchanged on exit */
618 p = (unsigned char*)(rrset[0]);
Simon Kelley394ff492015-03-29 22:17:14 +0100619 extract_name(header, plen, &p, name, 1, 0);
Simon Kelley5ada8882014-01-09 22:25:03 +0000620
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000621 if (key)
622 {
623 if (algo_in == algo && keytag_in == key_tag &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000624 verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000625 return STAT_SECURE;
626 }
627 else
628 {
629 /* iterate through all possible keys 4035 5.3.1 */
630 for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
Simon Kelleycc921df2019-01-02 22:48:59 +0000631 if (crecp->addr.key.algo == algo &&
632 crecp->addr.key.keytag == key_tag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000633 crecp->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000634 verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5107ace2014-02-23 10:48:32 +0000635 return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000636 }
637 }
638
639 return STAT_BOGUS;
640}
641
Simon Kelley2dbba342015-12-16 13:41:58 +0000642
Simon Kelley0fc2f312014-01-08 10:26:58 +0000643/* The DNS packet is expected to contain the answer to a DNSKEY query.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000644 Put all DNSKEYs in the answer which are valid into the cache.
645 return codes:
Simon Kelley3b799c82015-12-17 16:58:04 +0000646 STAT_OK Done, key(s) in cache.
647 STAT_BOGUS No DNSKEYs found, which can be validated with DS,
648 or self-sign for DNSKEY RRset is not valid, bad packet.
649 STAT_NEED_DS DS records to validate a key not found, name in keyname
650 STAT_NEED_KEY DNSKEY records to validate a key not found, name in keyname
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000651*/
652int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
653{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000654 unsigned char *psave, *p = (unsigned char *)(header+1);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000655 struct crec *crecp, *recp1;
Simon Kelley93be5b12015-12-15 12:04:40 +0000656 int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000657 struct blockdata *key;
Simon Kelleycc921df2019-01-02 22:48:59 +0000658 union all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000659
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000660 if (ntohs(header->qdcount) != 1 ||
Simon Kelley394ff492015-03-29 22:17:14 +0100661 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +0000662 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000663
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000664 GETSHORT(qtype, p);
665 GETSHORT(qclass, p);
666
Simon Kelley97e618a2015-01-07 21:55:43 +0000667 if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000668 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000669
Simon Kelleyb8eac192014-02-27 14:30:03 +0000670 /* See if we have cached a DS record which validates this key */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000671 if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
672 {
673 strcpy(keyname, name);
674 return STAT_NEED_DS;
675 }
Simon Kelleyb8eac192014-02-27 14:30:03 +0000676
Simon Kelley0fc2f312014-01-08 10:26:58 +0000677 /* NOTE, we need to find ONE DNSKEY which matches the DS */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000678 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000679 {
680 /* Ensure we have type, class TTL and length */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000681 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +0000682 return STAT_BOGUS; /* bad packet */
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000683
684 GETSHORT(qtype, p);
685 GETSHORT(qclass, p);
686 GETLONG(ttl, p);
687 GETSHORT(rdlen, p);
Simon Kelley6f468102014-01-26 23:39:17 +0000688
Simon Kelley0fc2f312014-01-08 10:26:58 +0000689 if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000690 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000691
Simon Kelley6f468102014-01-26 23:39:17 +0000692 if (qclass != class || qtype != T_DNSKEY || rc == 2)
693 {
694 p += rdlen;
695 continue;
696 }
697
Simon Kelley0fc2f312014-01-08 10:26:58 +0000698 psave = p;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000699
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000700 GETSHORT(flags, p);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000701 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000702 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000703 algo = *p++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000704 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000705 key = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000706
Simon Kelleye7829ae2014-01-22 22:21:51 +0000707 /* key must have zone key flag set */
708 if (flags & 0x100)
709 key = blockdata_alloc((char*)p, rdlen - 4);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000710
711 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000712
Simon Kelley0fc2f312014-01-08 10:26:58 +0000713 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000714 {
715 if (key)
716 blockdata_free(key);
Simon Kelley87070192014-03-01 20:48:24 +0000717 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000718 }
719
Simon Kelleye7829ae2014-01-22 22:21:51 +0000720 /* No zone key flag or malloc failure */
721 if (!key)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000722 continue;
723
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000724 for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000725 {
726 void *ctx;
727 unsigned char *digest, *ds_digest;
728 const struct nettle_hash *hash;
Simon Kelley9a31b682015-12-15 10:20:39 +0000729 int sigcnt, rrcnt;
730
Simon Kelleycc921df2019-01-02 22:48:59 +0000731 if (recp1->addr.ds.algo == algo &&
732 recp1->addr.ds.keytag == keytag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000733 recp1->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000734 (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
Simon Kelley86bec2d2014-01-13 21:31:20 +0000735 hash_init(hash, &ctx, &digest))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000736
Simon Kelley86bec2d2014-01-13 21:31:20 +0000737 {
738 int wire_len = to_wire(name);
739
740 /* Note that digest may be different between DSs, so
741 we can't move this outside the loop. */
742 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
743 hash->update(ctx, (unsigned int)rdlen, psave);
744 hash->digest(ctx, hash->digest_size, digest);
745
746 from_wire(name);
747
Simon Kelley9a31b682015-12-15 10:20:39 +0000748 if (!(recp1->flags & F_NEG) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000749 recp1->addr.ds.keylen == (int)hash->digest_size &&
750 (ds_digest = blockdata_retrieve(recp1->addr.ds.keydata, recp1->addr.ds.keylen, NULL)) &&
751 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
Simon Kelley9a31b682015-12-15 10:20:39 +0000752 explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
753 sigcnt != 0 && rrcnt != 0 &&
754 validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
755 NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000756 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000757 valid = 1;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000758 break;
759 }
760 }
761 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000762 blockdata_free(key);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000763 }
764
765 if (valid)
766 {
Simon Kelley93be5b12015-12-15 12:04:40 +0000767 /* DNSKEY RRset determined to be OK, now cache it. */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000768 cache_start_insert();
769
770 p = skip_questions(header, plen);
771
772 for (j = ntohs(header->ancount); j != 0; j--)
773 {
774 /* Ensure we have type, class TTL and length */
775 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +0000776 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000777
778 GETSHORT(qtype, p);
779 GETSHORT(qclass, p);
780 GETLONG(ttl, p);
781 GETSHORT(rdlen, p);
Simon Kelley8d718cb2014-02-03 16:27:37 +0000782
783 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000784 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000785
Simon Kelley8d718cb2014-02-03 16:27:37 +0000786 if (qclass == class && rc == 1)
Simon Kelleye7829ae2014-01-22 22:21:51 +0000787 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000788 psave = p;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000789
Simon Kelley8d718cb2014-02-03 16:27:37 +0000790 if (qtype == T_DNSKEY)
791 {
792 if (rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000793 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000794
795 GETSHORT(flags, p);
796 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000797 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000798 algo = *p++;
799 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
800
Simon Kelley8d718cb2014-02-03 16:27:37 +0000801 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
802 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000803 a.key.keylen = rdlen - 4;
804 a.key.keydata = key;
805 a.key.algo = algo;
806 a.key.keytag = keytag;
807 a.key.flags = flags;
Simon Kelleyab194ed2019-01-01 01:35:30 +0000808
809 if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK))
Simon Kelley93be5b12015-12-15 12:04:40 +0000810 {
811 blockdata_free(key);
812 return STAT_BOGUS;
813 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000814 else
815 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000816 a.log.keytag = keytag;
817 a.log.algo = algo;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100818 if (algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000819 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000820 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000821 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
Simon Kelley8d718cb2014-02-03 16:27:37 +0000822 }
823 }
824 }
Simon Kelley93be5b12015-12-15 12:04:40 +0000825
Simon Kelley8d718cb2014-02-03 16:27:37 +0000826 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000827 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000828
Simon Kelleye7829ae2014-01-22 22:21:51 +0000829 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000830 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000831 }
832
Simon Kelley0fc2f312014-01-08 10:26:58 +0000833 /* commit cache insert. */
834 cache_end_insert();
Simon Kelley9a31b682015-12-15 10:20:39 +0000835 return STAT_OK;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000836 }
837
Simon Kelley25cf5e32015-01-09 15:53:03 +0000838 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
Simon Kelley0fc2f312014-01-08 10:26:58 +0000839 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000840}
Simon Kelley0fc2f312014-01-08 10:26:58 +0000841
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000842/* The DNS packet is expected to contain the answer to a DS query
843 Put all DSs in the answer which are valid into the cache.
Simon Kelley9a31b682015-12-15 10:20:39 +0000844 Also handles replies which prove that there's no DS at this location,
845 either because the zone is unsigned or this isn't a zone cut. These are
846 cached too.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000847 return codes:
Simon Kelley9a31b682015-12-15 10:20:39 +0000848 STAT_OK At least one valid DS found and in cache.
Simon Kelley97e618a2015-01-07 21:55:43 +0000849 STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000850 STAT_NEED_KEY DNSKEY records to validate a DS not found, name in keyname
Simon Kelley9a31b682015-12-15 10:20:39 +0000851 STAT_NEED_DS DS record needed.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000852*/
853
854int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
855{
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000856 unsigned char *p = (unsigned char *)(header+1);
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000857 int qtype, qclass, rc, i, neganswer, nons;
858 int aclass, atype, rdlen;
859 unsigned long ttl;
Simon Kelleycc921df2019-01-02 22:48:59 +0000860 union all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000861
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000862 if (ntohs(header->qdcount) != 1 ||
Simon Kelleyb8eac192014-02-27 14:30:03 +0000863 !(p = skip_name(p, header, plen, 4)))
Simon Kelley87070192014-03-01 20:48:24 +0000864 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000865
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000866 GETSHORT(qtype, p);
867 GETSHORT(qclass, p);
868
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000869 if (qtype != T_DS || qclass != class)
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000870 rc = STAT_BOGUS;
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000871 else
Simon Kelley7f008432018-04-15 20:01:49 +0100872 rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
Simon Kelley97e618a2015-01-07 21:55:43 +0000873
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000874 if (rc == STAT_INSECURE)
Simon Kelley7f008432018-04-15 20:01:49 +0100875 {
Simon Kelleyf84e6742018-05-04 16:29:57 +0100876 my_syslog(LOG_WARNING, _("Insecure DS reply received, do upstream DNS servers support DNSSEC?"));
Simon Kelley7f008432018-04-15 20:01:49 +0100877 rc = STAT_BOGUS;
878 }
879
Simon Kelleyb8eac192014-02-27 14:30:03 +0000880 p = (unsigned char *)(header+1);
Simon Kelley394ff492015-03-29 22:17:14 +0100881 extract_name(header, plen, &p, name, 1, 4);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000882 p += 4; /* qtype, qclass */
883
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000884 /* If the key needed to validate the DS is on the same domain as the DS, we'll
885 loop getting nowhere. Stop that now. This can happen of the DS answer comes
886 from the DS's zone, and not the parent zone. */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000887 if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
Simon Kelleyb8eac192014-02-27 14:30:03 +0000888 {
Simon Kelley25cf5e32015-01-09 15:53:03 +0000889 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
Simon Kelley97e618a2015-01-07 21:55:43 +0000890 return STAT_BOGUS;
891 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000892
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000893 if (rc != STAT_SECURE)
894 return rc;
895
896 if (!neganswer)
Simon Kelley97e618a2015-01-07 21:55:43 +0000897 {
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000898 cache_start_insert();
899
900 for (i = 0; i < ntohs(header->ancount); i++)
901 {
902 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
903 return STAT_BOGUS; /* bad packet */
904
905 GETSHORT(atype, p);
906 GETSHORT(aclass, p);
907 GETLONG(ttl, p);
908 GETSHORT(rdlen, p);
909
910 if (!CHECK_LEN(header, p, plen, rdlen))
911 return STAT_BOGUS; /* bad packet */
912
913 if (aclass == class && atype == T_DS && rc == 1)
914 {
915 int algo, digest, keytag;
916 unsigned char *psave = p;
917 struct blockdata *key;
Simon Kelleyab194ed2019-01-01 01:35:30 +0000918
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000919 if (rdlen < 4)
920 return STAT_BOGUS; /* bad packet */
921
922 GETSHORT(keytag, p);
923 algo = *p++;
924 digest = *p++;
925
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000926 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
927 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000928 a.ds.digest = digest;
929 a.ds.keydata = key;
930 a.ds.algo = algo;
931 a.ds.keytag = keytag;
932 a.ds.keylen = rdlen - 4;
Simon Kelleyab194ed2019-01-01 01:35:30 +0000933
934 if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000935 {
936 blockdata_free(key);
937 return STAT_BOGUS;
938 }
939 else
940 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000941 a.log.keytag = keytag;
942 a.log.algo = algo;
943 a.log.digest = digest;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100944 if (ds_digest_name(digest) && algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000945 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000946 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000947 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000948 }
949 }
950
951 p = psave;
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000952 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000953 if (!ADD_RDLEN(header, p, plen, rdlen))
954 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000955 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000956
957 cache_end_insert();
958
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000959 }
960 else
961 {
962 int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
963 unsigned long minttl = ULONG_MAX;
964
965 if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
966 return STAT_BOGUS;
967
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000968 if (RCODE(header) == NXDOMAIN)
969 flags |= F_NXDOMAIN;
970
Simon Kelley97e618a2015-01-07 21:55:43 +0000971 /* We only cache validated DS records, DNSSECOK flag hijacked
972 to store presence/absence of NS. */
973 if (nons)
974 flags &= ~F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000975
976 for (i = ntohs(header->nscount); i != 0; i--)
977 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000978 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +0000979 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000980
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000981 GETSHORT(atype, p);
982 GETSHORT(aclass, p);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000983 GETLONG(ttl, p);
984 GETSHORT(rdlen, p);
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000985
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000986 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000987 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000988
989 if (aclass != class || atype != T_SOA)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000990 {
991 p += rdlen;
992 continue;
993 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000994
Simon Kelleyb8eac192014-02-27 14:30:03 +0000995 if (ttl < minttl)
996 minttl = ttl;
997
998 /* MNAME */
999 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001000 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001001 /* RNAME */
1002 if (!(p = skip_name(p, header, plen, 20)))
Simon Kelley87070192014-03-01 20:48:24 +00001003 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001004 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
1005
1006 GETLONG(ttl, p); /* minTTL */
1007 if (ttl < minttl)
1008 minttl = ttl;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001009
1010 break;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001011 }
1012
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001013 if (i != 0)
1014 {
1015 cache_start_insert();
1016
Simon Kelley65a01b72018-12-31 23:56:33 +00001017 if (!cache_insert(name, NULL, class, now, ttl, flags))
Simon Kelley93be5b12015-12-15 12:04:40 +00001018 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001019
Simon Kelley97e618a2015-01-07 21:55:43 +00001020 cache_end_insert();
1021
Simon Kelley9a31b682015-12-15 10:20:39 +00001022 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001023 }
Simon Kelleyb8eac192014-02-27 14:30:03 +00001024 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001025
Simon Kelley9a31b682015-12-15 10:20:39 +00001026 return STAT_OK;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001027}
1028
Simon Kelley9a31b682015-12-15 10:20:39 +00001029
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001030/* 4034 6.1 */
1031static int hostname_cmp(const char *a, const char *b)
1032{
Simon Kelleydbf72122014-01-21 14:28:02 +00001033 char *sa, *ea, *ca, *sb, *eb, *cb;
1034 unsigned char ac, bc;
1035
1036 sa = ea = (char *)a + strlen(a);
1037 sb = eb = (char *)b + strlen(b);
1038
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001039 while (1)
1040 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001041 while (sa != a && *(sa-1) != '.')
1042 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001043
Simon Kelleydbf72122014-01-21 14:28:02 +00001044 while (sb != b && *(sb-1) != '.')
1045 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001046
Simon Kelleydbf72122014-01-21 14:28:02 +00001047 ca = sa;
1048 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001049
Simon Kelleydbf72122014-01-21 14:28:02 +00001050 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001051 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001052 if (ca == ea)
1053 {
1054 if (cb == eb)
1055 break;
1056
1057 return -1;
1058 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001059
Simon Kelleydbf72122014-01-21 14:28:02 +00001060 if (cb == eb)
1061 return 1;
1062
1063 ac = (unsigned char) *ca++;
1064 bc = (unsigned char) *cb++;
1065
1066 if (ac >= 'A' && ac <= 'Z')
1067 ac += 'a' - 'A';
1068 if (bc >= 'A' && bc <= 'Z')
1069 bc += 'a' - 'A';
1070
Simon Kelley979cdf92014-01-21 16:26:41 +00001071 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001072 return -1;
1073 else if (ac != bc)
1074 return 1;
1075 }
1076
1077
1078 if (sa == a)
1079 {
1080 if (sb == b)
1081 return 0;
1082
1083 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001084 }
1085
Simon Kelleydbf72122014-01-21 14:28:02 +00001086 if (sb == b)
1087 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001088
Simon Kelley3e86d312015-12-20 20:50:05 +00001089 ea = --sa;
1090 eb = --sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001091 }
1092}
1093
Simon Kelley4fe67442018-01-19 12:26:08 +00001094static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
1095 char *workspace1_in, char *workspace2, char *name, int type, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001096{
1097 int i, rc, rdlen;
1098 unsigned char *p, *psave;
1099 int offset = (type & 0xff) >> 3;
1100 int mask = 0x80 >> (type & 0x07);
Simon Kelley97e618a2015-01-07 21:55:43 +00001101
1102 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001103 *nons = 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001104
1105 /* Find NSEC record that proves name doesn't exist */
1106 for (i = 0; i < nsec_count; i++)
1107 {
Simon Kelley4fe67442018-01-19 12:26:08 +00001108 char *workspace1 = workspace1_in;
1109 int sig_labels, name_labels;
1110
Simon Kelley5107ace2014-02-23 10:48:32 +00001111 p = nsecs[i];
Simon Kelley394ff492015-03-29 22:17:14 +01001112 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001113 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001114 p += 8; /* class, type, TTL */
1115 GETSHORT(rdlen, p);
1116 psave = p;
Simon Kelley394ff492015-03-29 22:17:14 +01001117 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001118 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001119
1120 /* If NSEC comes from wildcard expansion, use original wildcard
1121 as name for computation. */
1122 sig_labels = *labels[i];
1123 name_labels = count_labels(workspace1);
1124
1125 if (sig_labels < name_labels)
1126 {
1127 int k;
1128 for (k = name_labels - sig_labels; k != 0; k--)
1129 {
1130 while (*workspace1 != '.' && *workspace1 != 0)
1131 workspace1++;
1132 if (k != 1 && *workspace1 == '.')
1133 workspace1++;
1134 }
1135
1136 workspace1--;
1137 *workspace1 = '*';
1138 }
1139
Simon Kelley5107ace2014-02-23 10:48:32 +00001140 rc = hostname_cmp(workspace1, name);
1141
1142 if (rc == 0)
1143 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001144 /* 4035 para 5.4. Last sentence */
1145 if (type == T_NSEC || type == T_RRSIG)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001146 return 1;
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001147
Simon Kelley5107ace2014-02-23 10:48:32 +00001148 /* NSEC with the same name as the RR we're testing, check
1149 that the type in question doesn't appear in the type map */
1150 rdlen -= p - psave;
1151 /* rdlen is now length of type map, and p points to it */
1152
Simon Kelley97e618a2015-01-07 21:55:43 +00001153 /* If we can prove that there's no NS record, return that information. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001154 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
1155 *nons = 0;
Simon Kelley97e618a2015-01-07 21:55:43 +00001156
Simon Kelley9a31b682015-12-15 10:20:39 +00001157 if (rdlen >= 2 && p[0] == 0)
1158 {
1159 /* A CNAME answer would also be valid, so if there's a CNAME is should
1160 have been returned. */
1161 if ((p[2] & (0x80 >> T_CNAME)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001162 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001163
1164 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001165 DS from the wrong side of the delegation. For the root DS,
1166 this is expected. */
1167 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001168 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001169 }
1170
Simon Kelley5107ace2014-02-23 10:48:32 +00001171 while (rdlen >= 2)
1172 {
1173 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001174 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001175
1176 if (p[0] == type >> 8)
1177 {
1178 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001179 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001180 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001181
Josh Soref730c6742017-02-06 16:14:04 +00001182 break; /* finished checking */
Simon Kelley5107ace2014-02-23 10:48:32 +00001183 }
1184
1185 rdlen -= p[1];
1186 p += p[1];
1187 }
1188
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001189 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001190 }
1191 else if (rc == -1)
1192 {
1193 /* Normal case, name falls between NSEC name and next domain name,
1194 wrap around case, name falls between NSEC name (rc == -1) and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001195 if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001196 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001197 }
1198 else
1199 {
1200 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001201 if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001202 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001203 }
1204 }
1205
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001206 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001207}
1208
1209/* return digest length, or zero on error */
1210static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1211 unsigned char *salt, int salt_len, int iterations)
1212{
1213 void *ctx;
1214 unsigned char *digest;
1215 int i;
1216
1217 if (!hash_init(hash, &ctx, &digest))
1218 return 0;
1219
1220 hash->update(ctx, to_wire(in), (unsigned char *)in);
1221 hash->update(ctx, salt_len, salt);
1222 hash->digest(ctx, hash->digest_size, digest);
1223
1224 for(i = 0; i < iterations; i++)
1225 {
1226 hash->update(ctx, hash->digest_size, digest);
1227 hash->update(ctx, salt_len, salt);
1228 hash->digest(ctx, hash->digest_size, digest);
1229 }
1230
1231 from_wire(in);
1232
1233 *out = digest;
1234 return hash->digest_size;
1235}
1236
1237/* Decode base32 to first "." or end of string */
1238static int base32_decode(char *in, unsigned char *out)
1239{
Simon Kelleya857daa2014-02-24 21:01:09 +00001240 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001241 unsigned char *p = out;
1242
Simon Kelleya857daa2014-02-24 21:01:09 +00001243 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001244 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001245 if (c >= '0' && c <= '9')
1246 c -= '0';
1247 else if (c >= 'a' && c <= 'v')
1248 c -= 'a', c += 10;
1249 else if (c >= 'A' && c <= 'V')
1250 c -= 'A', c += 10;
1251 else
1252 return 0;
1253
1254 for (mask = 0x10, i = 0; i < 5; i++)
1255 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001256 if (c & mask)
1257 oc |= 1;
1258 mask = mask >> 1;
1259 if (((++on) & 7) == 0)
1260 *p++ = oc;
1261 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001262 }
1263 }
1264
1265 if ((on & 7) != 0)
1266 return 0;
1267
1268 return p - out;
1269}
1270
Simon Kelleyfbc52052014-12-23 15:46:08 +00001271static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
Simon Kelleya969ba62018-01-20 23:08:38 +00001272 char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001273{
Simon Kelley9a31b682015-12-15 10:20:39 +00001274 int i, hash_len, salt_len, base32_len, rdlen, flags;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001275 unsigned char *p, *psave;
1276
1277 for (i = 0; i < nsec_count; i++)
1278 if ((p = nsecs[i]))
1279 {
Simon Kelley394ff492015-03-29 22:17:14 +01001280 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleyfbc52052014-12-23 15:46:08 +00001281 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
1282 return 0;
1283
1284 p += 8; /* class, type, TTL */
1285 GETSHORT(rdlen, p);
1286 psave = p;
Simon Kelley9a31b682015-12-15 10:20:39 +00001287 p++; /* algo */
1288 flags = *p++; /* flags */
1289 p += 2; /* iterations */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001290 salt_len = *p++; /* salt_len */
1291 p += salt_len; /* salt */
1292 hash_len = *p++; /* p now points to next hashed name */
1293
1294 if (!CHECK_LEN(header, p, plen, hash_len))
1295 return 0;
1296
1297 if (digest_len == base32_len && hash_len == base32_len)
1298 {
1299 int rc = memcmp(workspace2, digest, digest_len);
1300
1301 if (rc == 0)
1302 {
1303 /* We found an NSEC3 whose hashed name exactly matches the query, so
1304 we just need to check the type map. p points to the RR data for the record. */
1305
1306 int offset = (type & 0xff) >> 3;
1307 int mask = 0x80 >> (type & 0x07);
1308
1309 p += hash_len; /* skip next-domain hash */
1310 rdlen -= p - psave;
1311
1312 if (!CHECK_LEN(header, p, plen, rdlen))
1313 return 0;
1314
Simon Kelley9a31b682015-12-15 10:20:39 +00001315 if (rdlen >= 2 && p[0] == 0)
1316 {
Simon Kelleyec0628c2015-12-31 20:55:39 +00001317 /* If we can prove that there's no NS record, return that information. */
1318 if (nons && (p[2] & (0x80 >> T_NS)) != 0)
1319 *nons = 0;
1320
Simon Kelley9a31b682015-12-15 10:20:39 +00001321 /* A CNAME answer would also be valid, so if there's a CNAME is should
1322 have been returned. */
1323 if ((p[2] & (0x80 >> T_CNAME)) != 0)
1324 return 0;
1325
1326 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001327 DS from the wrong side of the delegation. For the root DS,
1328 this is expected. */
1329 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001330 return 0;
1331 }
1332
Simon Kelleyfbc52052014-12-23 15:46:08 +00001333 while (rdlen >= 2)
1334 {
1335 if (p[0] == type >> 8)
1336 {
1337 /* Does the NSEC3 say our type exists? */
1338 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001339 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001340
Josh Soref730c6742017-02-06 16:14:04 +00001341 break; /* finished checking */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001342 }
1343
1344 rdlen -= p[1];
1345 p += p[1];
1346 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001347
Simon Kelleyfbc52052014-12-23 15:46:08 +00001348 return 1;
1349 }
Simon Kelley4d25cf82015-06-06 23:13:57 +01001350 else if (rc < 0)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001351 {
1352 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1353 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001354 if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001355 {
1356 if ((flags & 0x01) && nons) /* opt out */
1357 *nons = 0;
1358
1359 return 1;
1360 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001361 }
1362 else
1363 {
1364 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001365 if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001366 {
1367 if ((flags & 0x01) && nons) /* opt out */
1368 *nons = 0;
1369
1370 return 1;
1371 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001372 }
1373 }
1374 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001375
Simon Kelleyfbc52052014-12-23 15:46:08 +00001376 return 0;
1377}
1378
Simon Kelley24187532014-02-24 21:46:44 +00001379static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
Simon Kelley97e618a2015-01-07 21:55:43 +00001380 char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001381{
Simon Kelleya857daa2014-02-24 21:01:09 +00001382 unsigned char *salt, *p, *digest;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001383 int digest_len, i, iterations, salt_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001384 struct nettle_hash const *hash;
1385 char *closest_encloser, *next_closest, *wildcard;
Simon Kelley97e618a2015-01-07 21:55:43 +00001386
1387 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001388 *nons = 1;
Simon Kelley97e618a2015-01-07 21:55:43 +00001389
Simon Kelley5107ace2014-02-23 10:48:32 +00001390 /* Look though the NSEC3 records to find the first one with
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001391 an algorithm we support.
Simon Kelley5107ace2014-02-23 10:48:32 +00001392
1393 Take the algo, iterations, and salt of that record
1394 as the ones we're going to use, and prune any
1395 that don't match. */
1396
1397 for (i = 0; i < nsec_count; i++)
1398 {
1399 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001400 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001401
1402 p += 10; /* type, class, TTL, rdlen */
1403 algo = *p++;
1404
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001405 if ((hash = hash_find(nsec3_digest_name(algo))))
Simon Kelley5107ace2014-02-23 10:48:32 +00001406 break; /* known algo */
1407 }
1408
1409 /* No usable NSEC3s */
1410 if (i == nsec_count)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001411 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001412
1413 p++; /* flags */
Simon Kelley40205a02016-03-14 21:24:00 +00001414
Simon Kelley5107ace2014-02-23 10:48:32 +00001415 GETSHORT (iterations, p);
Simon Kelley40205a02016-03-14 21:24:00 +00001416 /* Upper-bound iterations, to avoid DoS.
1417 Strictly, there are lower bounds for small keys, but
1418 since we don't have key size info here, at least limit
1419 to the largest bound, for 4096-bit keys. RFC 5155 10.3 */
1420 if (iterations > 2500)
1421 return 0;
1422
Simon Kelley5107ace2014-02-23 10:48:32 +00001423 salt_len = *p++;
1424 salt = p;
1425 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001426 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001427
1428 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1429 for (i = 0; i < nsec_count; i++)
1430 {
1431 unsigned char *nsec3p = nsecs[i];
Simon Kelleyce5732e2015-12-20 21:39:19 +00001432 int this_iter, flags;
Simon Kelley5107ace2014-02-23 10:48:32 +00001433
1434 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1435
1436 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001437 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001438
1439 p += 10; /* type, class, TTL, rdlen */
1440
1441 if (*p++ != algo)
1442 continue;
1443
Simon Kelleyce5732e2015-12-20 21:39:19 +00001444 flags = *p++; /* flags */
Simon Kelley5107ace2014-02-23 10:48:32 +00001445
Simon Kelleyce5732e2015-12-20 21:39:19 +00001446 /* 5155 8.2 */
1447 if (flags != 0 && flags != 1)
1448 continue;
1449
Simon Kelleya857daa2014-02-24 21:01:09 +00001450 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001451 if (this_iter != iterations)
1452 continue;
1453
1454 if (salt_len != *p++)
1455 continue;
1456
1457 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001458 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001459
1460 if (memcmp(p, salt, salt_len) != 0)
1461 continue;
1462
1463 /* All match, put the pointer back */
1464 nsecs[i] = nsec3p;
1465 }
1466
Simon Kelleyfbc52052014-12-23 15:46:08 +00001467 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001468 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001469
Simon Kelleya969ba62018-01-20 23:08:38 +00001470 if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons, count_labels(name)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001471 return 1;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001472
1473 /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
1474 or an answer inferred from a wildcard record. */
Simon Kelley5107ace2014-02-23 10:48:32 +00001475 closest_encloser = name;
1476 next_closest = NULL;
1477
1478 do
1479 {
1480 if (*closest_encloser == '.')
1481 closest_encloser++;
1482
Simon Kelleyfbc52052014-12-23 15:46:08 +00001483 if (wildname && hostname_isequal(closest_encloser, wildname))
1484 break;
1485
Simon Kelleya857daa2014-02-24 21:01:09 +00001486 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001487 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001488
1489 for (i = 0; i < nsec_count; i++)
1490 if ((p = nsecs[i]))
1491 {
Simon Kelley394ff492015-03-29 22:17:14 +01001492 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001493 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001494 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001495
Simon Kelleya857daa2014-02-24 21:01:09 +00001496 if (digest_len == base32_len &&
1497 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001498 break; /* Gotit */
1499 }
1500
1501 if (i != nsec_count)
1502 break;
1503
1504 next_closest = closest_encloser;
1505 }
1506 while ((closest_encloser = strchr(closest_encloser, '.')));
1507
Simon Kelleya7b27e82016-03-16 19:11:52 +00001508 if (!closest_encloser || !next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001509 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001510
Simon Kelley24187532014-02-24 21:46:44 +00001511 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001512 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001513 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001514
Simon Kelleya969ba62018-01-20 23:08:38 +00001515 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001516 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001517
1518 /* Finally, check that there's no seat of wildcard synthesis */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001519 if (!wildname)
1520 {
1521 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001522 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001523
1524 wildcard--;
1525 *wildcard = '*';
1526
1527 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001528 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001529
Simon Kelleya969ba62018-01-20 23:08:38 +00001530 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001531 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001532 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001533
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001534 return 1;
1535}
1536
1537static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
1538{
Simon Kelley4fe67442018-01-19 12:26:08 +00001539 static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
1540 static int nsecset_sz = 0, rrsig_labels_sz = 0;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001541
1542 int type_found = 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001543 unsigned char *auth_start, *p = skip_questions(header, plen);
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001544 int type, class, rdlen, i, nsecs_found;
1545
1546 /* Move to NS section */
1547 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1548 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001549
1550 auth_start = p;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001551
1552 for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
1553 {
1554 unsigned char *pstart = p;
1555
Simon Kelley4fe67442018-01-19 12:26:08 +00001556 if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001557 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001558
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001559 GETSHORT(type, p);
1560 GETSHORT(class, p);
1561 p += 4; /* TTL */
1562 GETSHORT(rdlen, p);
1563
1564 if (class == qclass && (type == T_NSEC || type == T_NSEC3))
1565 {
1566 /* No mixed NSECing 'round here, thankyouverymuch */
1567 if (type_found != 0 && type_found != type)
1568 return 0;
1569
1570 type_found = type;
1571
1572 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1573 return 0;
1574
Simon Kelley4fe67442018-01-19 12:26:08 +00001575 if (type == T_NSEC)
1576 {
1577 /* If we're looking for NSECs, find the corresponding SIGs, to
1578 extract the labels value, which we need in case the NSECs
1579 are the result of wildcard expansion.
1580 Note that the NSEC may not have been validated yet
1581 so if there are multiple SIGs, make sure the label value
1582 is the same in all, to avoid be duped by a rogue one.
1583 If there are no SIGs, that's an error */
1584 unsigned char *p1 = auth_start;
1585 int res, j, rdlen1, type1, class1;
1586
1587 if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
1588 return 0;
1589
1590 rrsig_labels[nsecs_found] = NULL;
1591
1592 for (j = ntohs(header->nscount); j != 0; j--)
1593 {
1594 if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
1595 return 0;
1596
1597 GETSHORT(type1, p1);
1598 GETSHORT(class1, p1);
1599 p1 += 4; /* TTL */
1600 GETSHORT(rdlen1, p1);
1601
1602 if (!CHECK_LEN(header, p1, plen, rdlen1))
1603 return 0;
1604
1605 if (res == 1 && class1 == qclass && type1 == T_RRSIG)
1606 {
1607 int type_covered;
1608 unsigned char *psav = p1;
1609
Simon Kelleycd7df612018-01-20 00:10:55 +00001610 if (rdlen1 < 18)
Simon Kelley4fe67442018-01-19 12:26:08 +00001611 return 0; /* bad packet */
1612
1613 GETSHORT(type_covered, p1);
1614
1615 if (type_covered == T_NSEC)
1616 {
1617 p1++; /* algo */
1618
1619 /* labels field must be the same in every SIG we find. */
1620 if (!rrsig_labels[nsecs_found])
1621 rrsig_labels[nsecs_found] = p1;
1622 else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
1623 return 0;
1624 }
1625 p1 = psav;
1626 }
1627
1628 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1629 return 0;
1630 }
1631
1632 /* Must have found at least one sig. */
1633 if (!rrsig_labels[nsecs_found])
1634 return 0;
1635 }
1636
1637 nsecset[nsecs_found++] = pstart;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001638 }
1639
1640 if (!ADD_RDLEN(header, p, plen, rdlen))
1641 return 0;
1642 }
1643
1644 if (type_found == T_NSEC)
Simon Kelley4fe67442018-01-19 12:26:08 +00001645 return prove_non_existence_nsec(header, plen, nsecset, rrsig_labels, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001646 else if (type_found == T_NSEC3)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001647 return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001648 else
1649 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001650}
Simon Kelley9a31b682015-12-15 10:20:39 +00001651
1652/* Check signing status of name.
1653 returns:
Simon Kelley3b799c82015-12-17 16:58:04 +00001654 STAT_SECURE zone is signed.
1655 STAT_INSECURE zone proved unsigned.
1656 STAT_NEED_DS require DS record of name returned in keyname.
1657 STAT_NEED_KEY require DNSKEY record of name returned in keyname.
Simon Kelley9a31b682015-12-15 10:20:39 +00001658 name returned unaltered.
1659*/
1660static int zone_status(char *name, int class, char *keyname, time_t now)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001661{
Simon Kelleya63b8b82016-01-12 11:28:58 +00001662 int name_start = strlen(name); /* for when TA is root */
Simon Kelley9a31b682015-12-15 10:20:39 +00001663 struct crec *crecp;
1664 char *p;
Simon Kelleya63b8b82016-01-12 11:28:58 +00001665
1666 /* First, work towards the root, looking for a trust anchor.
1667 This can either be one configured, or one previously cached.
1668 We can assume, if we don't find one first, that there is
1669 a trust anchor at the root. */
1670 for (p = name; p; p = strchr(p, '.'))
1671 {
1672 if (*p == '.')
1673 p++;
1674
1675 if (cache_find_by_name(NULL, p, now, F_DS))
1676 {
1677 name_start = p - name;
1678 break;
1679 }
1680 }
Simon Kelley367341f2016-01-12 15:58:23 +00001681
Simon Kelleya63b8b82016-01-12 11:28:58 +00001682 /* Now work away from the trust anchor */
Simon Kelley9a31b682015-12-15 10:20:39 +00001683 while (1)
1684 {
1685 strcpy(keyname, &name[name_start]);
1686
1687 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
1688 return STAT_NEED_DS;
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001689
Josh Soref730c6742017-02-06 16:14:04 +00001690 /* F_DNSSECOK misused in DS cache records to non-existence of NS record.
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001691 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
1692 but that's because there's no NS record either, ie this isn't the start
1693 of a zone. We only prove that the DNS tree below a node is unsigned when
1694 we prove that we're at a zone cut AND there's no DS record. */
1695 if (crecp->flags & F_NEG)
1696 {
1697 if (crecp->flags & F_DNSSECOK)
1698 return STAT_INSECURE; /* proved no DS here */
1699 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001700 else
Simon Kelley2dbba342015-12-16 13:41:58 +00001701 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001702 /* If all the DS records have digest and/or sig algos we don't support,
1703 then the zone is insecure. Note that if an algo
1704 appears in the DS, then RRSIGs for that algo MUST
1705 exist for each RRset: 4035 para 2.2 So if we find
1706 a DS here with digest and sig we can do, we're entitled
1707 to assume we can validate the zone and if we can't later,
1708 because an RRSIG is missing we return BOGUS.
1709 */
Simon Kelley2dbba342015-12-16 13:41:58 +00001710 do
1711 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001712 if (crecp->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001713 ds_digest_name(crecp->addr.ds.digest) &&
1714 algo_digest_name(crecp->addr.ds.algo))
Simon Kelleya86fdf42015-12-20 21:19:20 +00001715 break;
Simon Kelley2dbba342015-12-16 13:41:58 +00001716 }
1717 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
Simon Kelley2dbba342015-12-16 13:41:58 +00001718
Simon Kelleya86fdf42015-12-20 21:19:20 +00001719 if (!crecp)
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001720 return STAT_INSECURE;
Simon Kelley2dbba342015-12-16 13:41:58 +00001721 }
1722
Simon Kelley9a31b682015-12-15 10:20:39 +00001723 if (name_start == 0)
1724 break;
1725
1726 for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
1727
1728 if (p != name)
1729 p++;
1730
1731 name_start = p - name;
1732 }
1733
1734 return STAT_SECURE;
1735}
1736
1737/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3)
1738 Return code:
1739 STAT_SECURE if it validates.
1740 STAT_INSECURE at least one RRset not validated, because in unsigned zone.
1741 STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
1742 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
Simon Kelleya6004d72017-10-25 17:48:19 +01001743 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
1744
Simon Kelley373e9172017-12-01 22:40:56 +00001745 daemon->rr_status points to a char array which corressponds to the RRs in the
Simon Kelleya6004d72017-10-25 17:48:19 +01001746 answer section (only). This is set to 1 for each RR which is validated, and 0 for any which aren't.
Simon Kelley9a31b682015-12-15 10:20:39 +00001747*/
1748int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
Simon Kelley373e9172017-12-01 22:40:56 +00001749 int *class, int check_unsigned, int *neganswer, int *nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001750{
1751 static unsigned char **targets = NULL;
1752 static int target_sz = 0;
1753
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001754 unsigned char *ans_start, *p1, *p2;
Simon Kelleya6004d72017-10-25 17:48:19 +01001755 int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
Simon Kelley91421cb2018-10-18 19:21:55 +01001756 int i, j, rc = STAT_INSECURE;
Simon Kelleya6004d72017-10-25 17:48:19 +01001757 int secure = STAT_SECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001758
Simon Kelley373e9172017-12-01 22:40:56 +00001759 /* extend rr_status if necessary */
1760 if (daemon->rr_status_sz < ntohs(header->ancount))
1761 {
1762 char *new = whine_malloc(ntohs(header->ancount) + 64);
1763
1764 if (!new)
1765 return STAT_BOGUS;
1766
1767 free(daemon->rr_status);
1768 daemon->rr_status = new;
1769 daemon->rr_status_sz = ntohs(header->ancount) + 64;
1770 }
1771
1772 memset(daemon->rr_status, 0, ntohs(header->ancount));
Simon Kelleya6004d72017-10-25 17:48:19 +01001773
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001774 if (neganswer)
1775 *neganswer = 0;
1776
Simon Kelley87070192014-03-01 20:48:24 +00001777 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001778 return STAT_BOGUS;
1779
Simon Kelley87070192014-03-01 20:48:24 +00001780 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001781 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001782
Simon Kelley9a31b682015-12-15 10:20:39 +00001783 p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001784
Simon Kelley9a31b682015-12-15 10:20:39 +00001785 /* Find all the targets we're looking for answers to.
1786 The zeroth array element is for the query, subsequent ones
1787 for CNAME targets, unless the query is for a CNAME. */
1788
1789 if (!expand_workspace(&targets, &target_sz, 0))
1790 return STAT_BOGUS;
1791
1792 targets[0] = p1;
1793 targetidx = 1;
1794
Simon Kelley394ff492015-03-29 22:17:14 +01001795 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001796 return STAT_BOGUS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001797
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001798 GETSHORT(qtype, p1);
1799 GETSHORT(qclass, p1);
1800 ans_start = p1;
1801
Simon Kelley9a31b682015-12-15 10:20:39 +00001802 /* Can't validate an RRSIG query */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001803 if (qtype == T_RRSIG)
1804 return STAT_INSECURE;
Simon Kelleye3ec6f02015-06-12 21:39:11 +01001805
Simon Kelley9a31b682015-12-15 10:20:39 +00001806 if (qtype != T_CNAME)
1807 for (j = ntohs(header->ancount); j != 0; j--)
1808 {
1809 if (!(p1 = skip_name(p1, header, plen, 10)))
1810 return STAT_BOGUS; /* bad packet */
1811
1812 GETSHORT(type2, p1);
1813 p1 += 6; /* class, TTL */
1814 GETSHORT(rdlen2, p1);
1815
1816 if (type2 == T_CNAME)
1817 {
1818 if (!expand_workspace(&targets, &target_sz, targetidx))
1819 return STAT_BOGUS;
1820
1821 targets[targetidx++] = p1; /* pointer to target name */
1822 }
1823
1824 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1825 return STAT_BOGUS;
1826 }
1827
Simon Kelley0fc2f312014-01-08 10:26:58 +00001828 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001829 {
Simon Kelley91421cb2018-10-18 19:21:55 +01001830 if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
1831 return STAT_BOGUS;
1832
1833 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001834 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001835
1836 GETSHORT(type1, p1);
1837 GETSHORT(class1, p1);
1838 p1 += 4; /* TTL */
1839 GETSHORT(rdlen1, p1);
1840
1841 /* Don't try and validate RRSIGs! */
Simon Kelleya6004d72017-10-25 17:48:19 +01001842 if (type1 == T_RRSIG)
1843 continue;
1844
1845 /* Check if we've done this RRset already */
1846 for (p2 = ans_start, j = 0; j < i; j++)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001847 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001848 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1849 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001850
Simon Kelleya6004d72017-10-25 17:48:19 +01001851 GETSHORT(type2, p2);
1852 GETSHORT(class2, p2);
1853 p2 += 4; /* TTL */
1854 GETSHORT(rdlen2, p2);
1855
1856 if (type2 == type1 && class2 == class1 && rc == 1)
1857 break; /* Done it before: name, type, class all match. */
1858
1859 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1860 return STAT_BOGUS;
1861 }
1862
1863 if (j != i)
1864 {
1865 /* Done already: copy the validation status */
Simon Kelley373e9172017-12-01 22:40:56 +00001866 if (i < ntohs(header->ancount))
1867 daemon->rr_status[i] = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +01001868 }
1869 else
1870 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001871 /* Not done, validate now */
Simon Kelleya6004d72017-10-25 17:48:19 +01001872 int sigcnt, rrcnt;
1873 char *wildname;
1874
1875 if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
1876 return STAT_BOGUS;
1877
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001878 /* No signatures for RRset. We can be configured to assume this is OK and return an INSECURE result. */
Simon Kelleya6004d72017-10-25 17:48:19 +01001879 if (sigcnt == 0)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001880 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001881 if (check_unsigned)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001882 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001883 rc = zone_status(name, class1, keyname, now);
1884 if (rc == STAT_SECURE)
1885 rc = STAT_BOGUS;
1886 if (class)
1887 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001888 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001889 else
1890 rc = STAT_INSECURE;
Simon Kelley5107ace2014-02-23 10:48:32 +00001891
Simon Kelleya6004d72017-10-25 17:48:19 +01001892 if (rc != STAT_INSECURE)
1893 return rc;
1894 }
1895 else
1896 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001897 /* explore_rrset() gives us key name from sigs in keyname.
1898 Can't overwrite name here. */
1899 strcpy(daemon->workspacename, keyname);
1900 rc = zone_status(daemon->workspacename, class1, keyname, now);
Simon Kelleya6004d72017-10-25 17:48:19 +01001901
1902 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001903 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001904 if (class)
Simon Kelley3b799c82015-12-17 16:58:04 +00001905 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley9a31b682015-12-15 10:20:39 +00001906 return rc;
Simon Kelleya6004d72017-10-25 17:48:19 +01001907 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001908
Simon Kelleya6004d72017-10-25 17:48:19 +01001909 /* Zone is insecure, don't need to validate RRset */
1910 if (rc == STAT_SECURE)
Simon Kelley9a31b682015-12-15 10:20:39 +00001911 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001912 rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
1913 rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
1914
1915 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
1916 {
1917 if (class)
1918 *class = class1; /* Class for DS or DNSKEY */
1919 return rc;
1920 }
1921
Simon Kelley9a31b682015-12-15 10:20:39 +00001922 /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
Simon Kelleya6004d72017-10-25 17:48:19 +01001923
1924 /* Note that RR is validated */
Simon Kelley373e9172017-12-01 22:40:56 +00001925 if (i < ntohs(header->ancount))
1926 daemon->rr_status[i] = 1;
Simon Kelleya6004d72017-10-25 17:48:19 +01001927
Simon Kelley9a31b682015-12-15 10:20:39 +00001928 /* Note if we've validated either the answer to the question
1929 or the target of a CNAME. Any not noted will need NSEC or
1930 to be in unsigned space. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001931 for (j = 0; j <targetidx; j++)
1932 if ((p2 = targets[j]))
1933 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001934 int rc1;
1935 if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001936 return STAT_BOGUS; /* bad packet */
1937
Simon Kelleya6004d72017-10-25 17:48:19 +01001938 if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
Simon Kelley9a31b682015-12-15 10:20:39 +00001939 targets[j] = NULL;
1940 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001941
1942 /* An attacker replay a wildcard answer with a different
1943 answer and overlay a genuine RR. To prove this
1944 hasn't happened, the answer must prove that
1945 the genuine record doesn't exist. Check that here.
1946 Note that we may not yet have validated the NSEC/NSEC3 RRsets.
1947 That's not a problem since if the RRsets later fail
1948 we'll return BOGUS then. */
1949 if (rc == STAT_SECURE_WILDCARD &&
1950 !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001951 return STAT_BOGUS;
Simon Kelleya6004d72017-10-25 17:48:19 +01001952
1953 rc = STAT_SECURE;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001954 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001955 }
1956 }
1957
Simon Kelleya6004d72017-10-25 17:48:19 +01001958 if (rc == STAT_INSECURE)
1959 secure = STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001960 }
1961
Simon Kelley9a31b682015-12-15 10:20:39 +00001962 /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
Simon Kelley7f008432018-04-15 20:01:49 +01001963 if (secure == STAT_SECURE)
Simon Kelley4e72fec2018-04-11 22:49:31 +01001964 for (j = 0; j <targetidx; j++)
1965 if ((p2 = targets[j]))
1966 {
1967 if (neganswer)
1968 *neganswer = 1;
1969
1970 if (!extract_name(header, plen, &p2, name, 1, 10))
1971 return STAT_BOGUS; /* bad packet */
1972
1973 /* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
1974
1975 /* For anything other than a DS record, this situation is OK if either
1976 the answer is in an unsigned zone, or there's a NSEC records. */
1977 if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
1978 {
1979 /* Empty DS without NSECS */
1980 if (qtype == T_DS)
1981 return STAT_BOGUS;
1982
1983 if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
1984 {
1985 if (class)
1986 *class = qclass; /* Class for NEED_DS or NEED_KEY */
1987 return rc;
1988 }
1989
1990 return STAT_BOGUS; /* signed zone, no NSECs */
1991 }
1992 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001993
Simon Kelleya6004d72017-10-25 17:48:19 +01001994 return secure;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001995}
1996
1997
Giovanni Bajo3471f182012-04-25 17:49:16 +02001998/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001999int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02002000{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002001 if (alg == 1)
2002 {
2003 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
2004 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002005 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002006 }
2007 else
2008 {
Simon Kelley1633e302014-02-10 16:42:46 +00002009 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002010 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002011
Simon Kelley0fc2f312014-01-08 10:26:58 +00002012 for (i = 0; i < keylen; ++i)
2013 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002014
Simon Kelley0fc2f312014-01-08 10:26:58 +00002015 ac += (ac >> 16) & 0xffff;
2016 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002017 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002018}
2019
Simon Kelley33702ab2015-12-28 23:17:15 +00002020size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
Simon Kelleye1791f32018-10-06 23:23:23 +01002021 int type, int edns_pktsz)
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002022{
2023 unsigned char *p;
Simon Kelleya77cec82015-05-08 16:25:38 +01002024 size_t ret;
Giovanni Bajo0304d282012-05-02 03:29:52 +02002025
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002026 header->qdcount = htons(1);
2027 header->ancount = htons(0);
2028 header->nscount = htons(0);
2029 header->arcount = htons(0);
2030
2031 header->hb3 = HB3_RD;
2032 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002033 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2034 this allows it to select auth servers when one is returning bad data. */
2035 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002036
2037 /* ID filled in later */
2038
2039 p = (unsigned char *)(header+1);
2040
Simon Kelley0549c732017-09-25 18:17:11 +01002041 p = do_rfc1035_name(p, name, NULL);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002042 *p++ = 0;
2043 PUTSHORT(type, p);
2044 PUTSHORT(class, p);
2045
Simon Kelleya77cec82015-05-08 16:25:38 +01002046 ret = add_do_bit(header, p - (unsigned char *)header, end);
2047
Simon Kelley5bb88f02015-12-21 16:23:47 +00002048 if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
Simon Kelleya77cec82015-05-08 16:25:38 +01002049 PUTSHORT(edns_pktsz, p);
2050
2051 return ret;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002052}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002053
2054unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2055{
2056 int q;
2057 unsigned int len;
2058 unsigned char *p = (unsigned char *)(header+1);
2059 const struct nettle_hash *hash;
2060 void *ctx;
2061 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002062
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002063 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2064 return NULL;
2065
2066 for (q = ntohs(header->qdcount); q != 0; q--)
2067 {
Simon Kelley394ff492015-03-29 22:17:14 +01002068 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002069 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002070
2071 len = to_wire(name);
2072 hash->update(ctx, len, (unsigned char *)name);
2073 /* CRC the class and type as well */
2074 hash->update(ctx, 4, p);
2075
2076 p += 4;
2077 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002078 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002079 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002080
2081 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002082 return digest;
2083}
2084
Simon Kelley0fc2f312014-01-08 10:26:58 +00002085#endif /* HAVE_DNSSEC */