blob: 4fdc027b65faff0af94be560a69399b219409a46 [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 Kelley87070192014-03-01 20:48:24 +0000377 return STAT_BOGUS;
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 Kelley87070192014-03-01 20:48:24 +0000389 return STAT_BOGUS; /* 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 Kelley51ea3ca2014-01-22 19:31:38 +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 Kelleyebe95a82014-02-13 14:56:10 +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 Kelley51ea3ca2014-01-22 19:31:38 +0000658 struct 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 Kelley51ea3ca2014-01-22 19:31:38 +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 Kelley51ea3ca2014-01-22 19:31:38 +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) &&
749 recp1->addr.ds.keylen == (int)hash->digest_size &&
Simon Kelley824202e2014-01-23 20:59:46 +0000750 (ds_digest = blockdata_retrieve(recp1->addr.key.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 Kelley65a01b72018-12-31 23:56:33 +0000803 if (!(recp1 = cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
Simon Kelley93be5b12015-12-15 12:04:40 +0000804 {
805 blockdata_free(key);
806 return STAT_BOGUS;
807 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000808 else
809 {
Simon Kelley15379ea2015-12-21 18:31:55 +0000810 a.addr.log.keytag = keytag;
811 a.addr.log.algo = algo;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100812 if (algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000813 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000814 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000815 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
Simon Kelley8d718cb2014-02-03 16:27:37 +0000816
817 recp1->addr.key.keylen = rdlen - 4;
818 recp1->addr.key.keydata = key;
819 recp1->addr.key.algo = algo;
820 recp1->addr.key.keytag = keytag;
821 recp1->addr.key.flags = flags;
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;
860 struct 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;
918 struct crec *crecp;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000919
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000920 if (rdlen < 4)
921 return STAT_BOGUS; /* bad packet */
922
923 GETSHORT(keytag, p);
924 algo = *p++;
925 digest = *p++;
926
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000927 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
928 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000929 if (!(crecp = cache_insert(name, NULL, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000930 {
931 blockdata_free(key);
932 return STAT_BOGUS;
933 }
934 else
935 {
Simon Kelley15379ea2015-12-21 18:31:55 +0000936 a.addr.log.keytag = keytag;
937 a.addr.log.algo = algo;
938 a.addr.log.digest = digest;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100939 if (ds_digest_name(digest) && algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000940 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000941 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000942 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000943
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000944 crecp->addr.ds.digest = digest;
945 crecp->addr.ds.keydata = key;
946 crecp->addr.ds.algo = algo;
947 crecp->addr.ds.keytag = keytag;
948 crecp->addr.ds.keylen = rdlen - 4;
949 }
950 }
951
952 p = psave;
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000953 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000954 if (!ADD_RDLEN(header, p, plen, rdlen))
955 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000956 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000957
958 cache_end_insert();
959
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000960 }
961 else
962 {
963 int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
964 unsigned long minttl = ULONG_MAX;
965
966 if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
967 return STAT_BOGUS;
968
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000969 if (RCODE(header) == NXDOMAIN)
970 flags |= F_NXDOMAIN;
971
Simon Kelley97e618a2015-01-07 21:55:43 +0000972 /* We only cache validated DS records, DNSSECOK flag hijacked
973 to store presence/absence of NS. */
974 if (nons)
975 flags &= ~F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000976
977 for (i = ntohs(header->nscount); i != 0; i--)
978 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000979 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +0000980 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000981
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000982 GETSHORT(atype, p);
983 GETSHORT(aclass, p);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000984 GETLONG(ttl, p);
985 GETSHORT(rdlen, p);
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000986
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000987 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000988 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000989
990 if (aclass != class || atype != T_SOA)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000991 {
992 p += rdlen;
993 continue;
994 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000995
Simon Kelleyb8eac192014-02-27 14:30:03 +0000996 if (ttl < minttl)
997 minttl = ttl;
998
999 /* MNAME */
1000 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001001 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001002 /* RNAME */
1003 if (!(p = skip_name(p, header, plen, 20)))
Simon Kelley87070192014-03-01 20:48:24 +00001004 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001005 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
1006
1007 GETLONG(ttl, p); /* minTTL */
1008 if (ttl < minttl)
1009 minttl = ttl;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001010
1011 break;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001012 }
1013
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001014 if (i != 0)
1015 {
1016 cache_start_insert();
1017
Simon Kelley65a01b72018-12-31 23:56:33 +00001018 if (!cache_insert(name, NULL, class, now, ttl, flags))
Simon Kelley93be5b12015-12-15 12:04:40 +00001019 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001020
Simon Kelley97e618a2015-01-07 21:55:43 +00001021 cache_end_insert();
1022
Simon Kelley9a31b682015-12-15 10:20:39 +00001023 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001024 }
Simon Kelleyb8eac192014-02-27 14:30:03 +00001025 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001026
Simon Kelley9a31b682015-12-15 10:20:39 +00001027 return STAT_OK;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001028}
1029
Simon Kelley9a31b682015-12-15 10:20:39 +00001030
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001031/* 4034 6.1 */
1032static int hostname_cmp(const char *a, const char *b)
1033{
Simon Kelleydbf72122014-01-21 14:28:02 +00001034 char *sa, *ea, *ca, *sb, *eb, *cb;
1035 unsigned char ac, bc;
1036
1037 sa = ea = (char *)a + strlen(a);
1038 sb = eb = (char *)b + strlen(b);
1039
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001040 while (1)
1041 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001042 while (sa != a && *(sa-1) != '.')
1043 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001044
Simon Kelleydbf72122014-01-21 14:28:02 +00001045 while (sb != b && *(sb-1) != '.')
1046 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001047
Simon Kelleydbf72122014-01-21 14:28:02 +00001048 ca = sa;
1049 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001050
Simon Kelleydbf72122014-01-21 14:28:02 +00001051 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001052 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001053 if (ca == ea)
1054 {
1055 if (cb == eb)
1056 break;
1057
1058 return -1;
1059 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001060
Simon Kelleydbf72122014-01-21 14:28:02 +00001061 if (cb == eb)
1062 return 1;
1063
1064 ac = (unsigned char) *ca++;
1065 bc = (unsigned char) *cb++;
1066
1067 if (ac >= 'A' && ac <= 'Z')
1068 ac += 'a' - 'A';
1069 if (bc >= 'A' && bc <= 'Z')
1070 bc += 'a' - 'A';
1071
Simon Kelley979cdf92014-01-21 16:26:41 +00001072 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001073 return -1;
1074 else if (ac != bc)
1075 return 1;
1076 }
1077
1078
1079 if (sa == a)
1080 {
1081 if (sb == b)
1082 return 0;
1083
1084 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001085 }
1086
Simon Kelleydbf72122014-01-21 14:28:02 +00001087 if (sb == b)
1088 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001089
Simon Kelley3e86d312015-12-20 20:50:05 +00001090 ea = --sa;
1091 eb = --sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001092 }
1093}
1094
Simon Kelley4fe67442018-01-19 12:26:08 +00001095static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
1096 char *workspace1_in, char *workspace2, char *name, int type, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001097{
1098 int i, rc, rdlen;
1099 unsigned char *p, *psave;
1100 int offset = (type & 0xff) >> 3;
1101 int mask = 0x80 >> (type & 0x07);
Simon Kelley97e618a2015-01-07 21:55:43 +00001102
1103 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001104 *nons = 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001105
1106 /* Find NSEC record that proves name doesn't exist */
1107 for (i = 0; i < nsec_count; i++)
1108 {
Simon Kelley4fe67442018-01-19 12:26:08 +00001109 char *workspace1 = workspace1_in;
1110 int sig_labels, name_labels;
1111
Simon Kelley5107ace2014-02-23 10:48:32 +00001112 p = nsecs[i];
Simon Kelley394ff492015-03-29 22:17:14 +01001113 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001114 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001115 p += 8; /* class, type, TTL */
1116 GETSHORT(rdlen, p);
1117 psave = p;
Simon Kelley394ff492015-03-29 22:17:14 +01001118 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001119 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001120
1121 /* If NSEC comes from wildcard expansion, use original wildcard
1122 as name for computation. */
1123 sig_labels = *labels[i];
1124 name_labels = count_labels(workspace1);
1125
1126 if (sig_labels < name_labels)
1127 {
1128 int k;
1129 for (k = name_labels - sig_labels; k != 0; k--)
1130 {
1131 while (*workspace1 != '.' && *workspace1 != 0)
1132 workspace1++;
1133 if (k != 1 && *workspace1 == '.')
1134 workspace1++;
1135 }
1136
1137 workspace1--;
1138 *workspace1 = '*';
1139 }
1140
Simon Kelley5107ace2014-02-23 10:48:32 +00001141 rc = hostname_cmp(workspace1, name);
1142
1143 if (rc == 0)
1144 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001145 /* 4035 para 5.4. Last sentence */
1146 if (type == T_NSEC || type == T_RRSIG)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001147 return 1;
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001148
Simon Kelley5107ace2014-02-23 10:48:32 +00001149 /* NSEC with the same name as the RR we're testing, check
1150 that the type in question doesn't appear in the type map */
1151 rdlen -= p - psave;
1152 /* rdlen is now length of type map, and p points to it */
1153
Simon Kelley97e618a2015-01-07 21:55:43 +00001154 /* If we can prove that there's no NS record, return that information. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001155 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
1156 *nons = 0;
Simon Kelley97e618a2015-01-07 21:55:43 +00001157
Simon Kelley9a31b682015-12-15 10:20:39 +00001158 if (rdlen >= 2 && p[0] == 0)
1159 {
1160 /* A CNAME answer would also be valid, so if there's a CNAME is should
1161 have been returned. */
1162 if ((p[2] & (0x80 >> T_CNAME)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001163 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001164
1165 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001166 DS from the wrong side of the delegation. For the root DS,
1167 this is expected. */
1168 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001169 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001170 }
1171
Simon Kelley5107ace2014-02-23 10:48:32 +00001172 while (rdlen >= 2)
1173 {
1174 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001175 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001176
1177 if (p[0] == type >> 8)
1178 {
1179 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001180 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001181 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001182
Josh Soref730c6742017-02-06 16:14:04 +00001183 break; /* finished checking */
Simon Kelley5107ace2014-02-23 10:48:32 +00001184 }
1185
1186 rdlen -= p[1];
1187 p += p[1];
1188 }
1189
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001190 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001191 }
1192 else if (rc == -1)
1193 {
1194 /* Normal case, name falls between NSEC name and next domain name,
1195 wrap around case, name falls between NSEC name (rc == -1) and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001196 if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001197 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001198 }
1199 else
1200 {
1201 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001202 if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001203 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001204 }
1205 }
1206
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001207 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001208}
1209
1210/* return digest length, or zero on error */
1211static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1212 unsigned char *salt, int salt_len, int iterations)
1213{
1214 void *ctx;
1215 unsigned char *digest;
1216 int i;
1217
1218 if (!hash_init(hash, &ctx, &digest))
1219 return 0;
1220
1221 hash->update(ctx, to_wire(in), (unsigned char *)in);
1222 hash->update(ctx, salt_len, salt);
1223 hash->digest(ctx, hash->digest_size, digest);
1224
1225 for(i = 0; i < iterations; i++)
1226 {
1227 hash->update(ctx, hash->digest_size, digest);
1228 hash->update(ctx, salt_len, salt);
1229 hash->digest(ctx, hash->digest_size, digest);
1230 }
1231
1232 from_wire(in);
1233
1234 *out = digest;
1235 return hash->digest_size;
1236}
1237
1238/* Decode base32 to first "." or end of string */
1239static int base32_decode(char *in, unsigned char *out)
1240{
Simon Kelleya857daa2014-02-24 21:01:09 +00001241 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001242 unsigned char *p = out;
1243
Simon Kelleya857daa2014-02-24 21:01:09 +00001244 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001245 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001246 if (c >= '0' && c <= '9')
1247 c -= '0';
1248 else if (c >= 'a' && c <= 'v')
1249 c -= 'a', c += 10;
1250 else if (c >= 'A' && c <= 'V')
1251 c -= 'A', c += 10;
1252 else
1253 return 0;
1254
1255 for (mask = 0x10, i = 0; i < 5; i++)
1256 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001257 if (c & mask)
1258 oc |= 1;
1259 mask = mask >> 1;
1260 if (((++on) & 7) == 0)
1261 *p++ = oc;
1262 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001263 }
1264 }
1265
1266 if ((on & 7) != 0)
1267 return 0;
1268
1269 return p - out;
1270}
1271
Simon Kelleyfbc52052014-12-23 15:46:08 +00001272static 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 +00001273 char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001274{
Simon Kelley9a31b682015-12-15 10:20:39 +00001275 int i, hash_len, salt_len, base32_len, rdlen, flags;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001276 unsigned char *p, *psave;
1277
1278 for (i = 0; i < nsec_count; i++)
1279 if ((p = nsecs[i]))
1280 {
Simon Kelley394ff492015-03-29 22:17:14 +01001281 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleyfbc52052014-12-23 15:46:08 +00001282 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
1283 return 0;
1284
1285 p += 8; /* class, type, TTL */
1286 GETSHORT(rdlen, p);
1287 psave = p;
Simon Kelley9a31b682015-12-15 10:20:39 +00001288 p++; /* algo */
1289 flags = *p++; /* flags */
1290 p += 2; /* iterations */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001291 salt_len = *p++; /* salt_len */
1292 p += salt_len; /* salt */
1293 hash_len = *p++; /* p now points to next hashed name */
1294
1295 if (!CHECK_LEN(header, p, plen, hash_len))
1296 return 0;
1297
1298 if (digest_len == base32_len && hash_len == base32_len)
1299 {
1300 int rc = memcmp(workspace2, digest, digest_len);
1301
1302 if (rc == 0)
1303 {
1304 /* We found an NSEC3 whose hashed name exactly matches the query, so
1305 we just need to check the type map. p points to the RR data for the record. */
1306
1307 int offset = (type & 0xff) >> 3;
1308 int mask = 0x80 >> (type & 0x07);
1309
1310 p += hash_len; /* skip next-domain hash */
1311 rdlen -= p - psave;
1312
1313 if (!CHECK_LEN(header, p, plen, rdlen))
1314 return 0;
1315
Simon Kelley9a31b682015-12-15 10:20:39 +00001316 if (rdlen >= 2 && p[0] == 0)
1317 {
Simon Kelleyec0628c2015-12-31 20:55:39 +00001318 /* If we can prove that there's no NS record, return that information. */
1319 if (nons && (p[2] & (0x80 >> T_NS)) != 0)
1320 *nons = 0;
1321
Simon Kelley9a31b682015-12-15 10:20:39 +00001322 /* A CNAME answer would also be valid, so if there's a CNAME is should
1323 have been returned. */
1324 if ((p[2] & (0x80 >> T_CNAME)) != 0)
1325 return 0;
1326
1327 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001328 DS from the wrong side of the delegation. For the root DS,
1329 this is expected. */
1330 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001331 return 0;
1332 }
1333
Simon Kelleyfbc52052014-12-23 15:46:08 +00001334 while (rdlen >= 2)
1335 {
1336 if (p[0] == type >> 8)
1337 {
1338 /* Does the NSEC3 say our type exists? */
1339 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001340 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001341
Josh Soref730c6742017-02-06 16:14:04 +00001342 break; /* finished checking */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001343 }
1344
1345 rdlen -= p[1];
1346 p += p[1];
1347 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001348
Simon Kelleyfbc52052014-12-23 15:46:08 +00001349 return 1;
1350 }
Simon Kelley4d25cf82015-06-06 23:13:57 +01001351 else if (rc < 0)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001352 {
1353 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1354 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001355 if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001356 {
1357 if ((flags & 0x01) && nons) /* opt out */
1358 *nons = 0;
1359
1360 return 1;
1361 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001362 }
1363 else
1364 {
1365 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001366 if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001367 {
1368 if ((flags & 0x01) && nons) /* opt out */
1369 *nons = 0;
1370
1371 return 1;
1372 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001373 }
1374 }
1375 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001376
Simon Kelleyfbc52052014-12-23 15:46:08 +00001377 return 0;
1378}
1379
Simon Kelley24187532014-02-24 21:46:44 +00001380static 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 +00001381 char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001382{
Simon Kelleya857daa2014-02-24 21:01:09 +00001383 unsigned char *salt, *p, *digest;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001384 int digest_len, i, iterations, salt_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001385 struct nettle_hash const *hash;
1386 char *closest_encloser, *next_closest, *wildcard;
Simon Kelley97e618a2015-01-07 21:55:43 +00001387
1388 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001389 *nons = 1;
Simon Kelley97e618a2015-01-07 21:55:43 +00001390
Simon Kelley5107ace2014-02-23 10:48:32 +00001391 /* Look though the NSEC3 records to find the first one with
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001392 an algorithm we support.
Simon Kelley5107ace2014-02-23 10:48:32 +00001393
1394 Take the algo, iterations, and salt of that record
1395 as the ones we're going to use, and prune any
1396 that don't match. */
1397
1398 for (i = 0; i < nsec_count; i++)
1399 {
1400 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001401 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001402
1403 p += 10; /* type, class, TTL, rdlen */
1404 algo = *p++;
1405
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001406 if ((hash = hash_find(nsec3_digest_name(algo))))
Simon Kelley5107ace2014-02-23 10:48:32 +00001407 break; /* known algo */
1408 }
1409
1410 /* No usable NSEC3s */
1411 if (i == nsec_count)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001412 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001413
1414 p++; /* flags */
Simon Kelley40205a02016-03-14 21:24:00 +00001415
Simon Kelley5107ace2014-02-23 10:48:32 +00001416 GETSHORT (iterations, p);
Simon Kelley40205a02016-03-14 21:24:00 +00001417 /* Upper-bound iterations, to avoid DoS.
1418 Strictly, there are lower bounds for small keys, but
1419 since we don't have key size info here, at least limit
1420 to the largest bound, for 4096-bit keys. RFC 5155 10.3 */
1421 if (iterations > 2500)
1422 return 0;
1423
Simon Kelley5107ace2014-02-23 10:48:32 +00001424 salt_len = *p++;
1425 salt = p;
1426 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001427 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001428
1429 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1430 for (i = 0; i < nsec_count; i++)
1431 {
1432 unsigned char *nsec3p = nsecs[i];
Simon Kelleyce5732e2015-12-20 21:39:19 +00001433 int this_iter, flags;
Simon Kelley5107ace2014-02-23 10:48:32 +00001434
1435 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1436
1437 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001438 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001439
1440 p += 10; /* type, class, TTL, rdlen */
1441
1442 if (*p++ != algo)
1443 continue;
1444
Simon Kelleyce5732e2015-12-20 21:39:19 +00001445 flags = *p++; /* flags */
Simon Kelley5107ace2014-02-23 10:48:32 +00001446
Simon Kelleyce5732e2015-12-20 21:39:19 +00001447 /* 5155 8.2 */
1448 if (flags != 0 && flags != 1)
1449 continue;
1450
Simon Kelleya857daa2014-02-24 21:01:09 +00001451 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001452 if (this_iter != iterations)
1453 continue;
1454
1455 if (salt_len != *p++)
1456 continue;
1457
1458 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001459 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001460
1461 if (memcmp(p, salt, salt_len) != 0)
1462 continue;
1463
1464 /* All match, put the pointer back */
1465 nsecs[i] = nsec3p;
1466 }
1467
Simon Kelleyfbc52052014-12-23 15:46:08 +00001468 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001469 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001470
Simon Kelleya969ba62018-01-20 23:08:38 +00001471 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 +00001472 return 1;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001473
1474 /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
1475 or an answer inferred from a wildcard record. */
Simon Kelley5107ace2014-02-23 10:48:32 +00001476 closest_encloser = name;
1477 next_closest = NULL;
1478
1479 do
1480 {
1481 if (*closest_encloser == '.')
1482 closest_encloser++;
1483
Simon Kelleyfbc52052014-12-23 15:46:08 +00001484 if (wildname && hostname_isequal(closest_encloser, wildname))
1485 break;
1486
Simon Kelleya857daa2014-02-24 21:01:09 +00001487 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001488 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001489
1490 for (i = 0; i < nsec_count; i++)
1491 if ((p = nsecs[i]))
1492 {
Simon Kelley394ff492015-03-29 22:17:14 +01001493 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001494 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001495 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001496
Simon Kelleya857daa2014-02-24 21:01:09 +00001497 if (digest_len == base32_len &&
1498 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001499 break; /* Gotit */
1500 }
1501
1502 if (i != nsec_count)
1503 break;
1504
1505 next_closest = closest_encloser;
1506 }
1507 while ((closest_encloser = strchr(closest_encloser, '.')));
1508
Simon Kelleya7b27e82016-03-16 19:11:52 +00001509 if (!closest_encloser || !next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001510 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001511
Simon Kelley24187532014-02-24 21:46:44 +00001512 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001513 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001514 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001515
Simon Kelleya969ba62018-01-20 23:08:38 +00001516 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001517 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001518
1519 /* Finally, check that there's no seat of wildcard synthesis */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001520 if (!wildname)
1521 {
1522 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001523 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001524
1525 wildcard--;
1526 *wildcard = '*';
1527
1528 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001529 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001530
Simon Kelleya969ba62018-01-20 23:08:38 +00001531 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001532 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001533 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001534
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001535 return 1;
1536}
1537
1538static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
1539{
Simon Kelley4fe67442018-01-19 12:26:08 +00001540 static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
1541 static int nsecset_sz = 0, rrsig_labels_sz = 0;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001542
1543 int type_found = 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001544 unsigned char *auth_start, *p = skip_questions(header, plen);
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001545 int type, class, rdlen, i, nsecs_found;
1546
1547 /* Move to NS section */
1548 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1549 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001550
1551 auth_start = p;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001552
1553 for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
1554 {
1555 unsigned char *pstart = p;
1556
Simon Kelley4fe67442018-01-19 12:26:08 +00001557 if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001558 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001559
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001560 GETSHORT(type, p);
1561 GETSHORT(class, p);
1562 p += 4; /* TTL */
1563 GETSHORT(rdlen, p);
1564
1565 if (class == qclass && (type == T_NSEC || type == T_NSEC3))
1566 {
1567 /* No mixed NSECing 'round here, thankyouverymuch */
1568 if (type_found != 0 && type_found != type)
1569 return 0;
1570
1571 type_found = type;
1572
1573 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1574 return 0;
1575
Simon Kelley4fe67442018-01-19 12:26:08 +00001576 if (type == T_NSEC)
1577 {
1578 /* If we're looking for NSECs, find the corresponding SIGs, to
1579 extract the labels value, which we need in case the NSECs
1580 are the result of wildcard expansion.
1581 Note that the NSEC may not have been validated yet
1582 so if there are multiple SIGs, make sure the label value
1583 is the same in all, to avoid be duped by a rogue one.
1584 If there are no SIGs, that's an error */
1585 unsigned char *p1 = auth_start;
1586 int res, j, rdlen1, type1, class1;
1587
1588 if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
1589 return 0;
1590
1591 rrsig_labels[nsecs_found] = NULL;
1592
1593 for (j = ntohs(header->nscount); j != 0; j--)
1594 {
1595 if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
1596 return 0;
1597
1598 GETSHORT(type1, p1);
1599 GETSHORT(class1, p1);
1600 p1 += 4; /* TTL */
1601 GETSHORT(rdlen1, p1);
1602
1603 if (!CHECK_LEN(header, p1, plen, rdlen1))
1604 return 0;
1605
1606 if (res == 1 && class1 == qclass && type1 == T_RRSIG)
1607 {
1608 int type_covered;
1609 unsigned char *psav = p1;
1610
Simon Kelleycd7df612018-01-20 00:10:55 +00001611 if (rdlen1 < 18)
Simon Kelley4fe67442018-01-19 12:26:08 +00001612 return 0; /* bad packet */
1613
1614 GETSHORT(type_covered, p1);
1615
1616 if (type_covered == T_NSEC)
1617 {
1618 p1++; /* algo */
1619
1620 /* labels field must be the same in every SIG we find. */
1621 if (!rrsig_labels[nsecs_found])
1622 rrsig_labels[nsecs_found] = p1;
1623 else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
1624 return 0;
1625 }
1626 p1 = psav;
1627 }
1628
1629 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1630 return 0;
1631 }
1632
1633 /* Must have found at least one sig. */
1634 if (!rrsig_labels[nsecs_found])
1635 return 0;
1636 }
1637
1638 nsecset[nsecs_found++] = pstart;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001639 }
1640
1641 if (!ADD_RDLEN(header, p, plen, rdlen))
1642 return 0;
1643 }
1644
1645 if (type_found == T_NSEC)
Simon Kelley4fe67442018-01-19 12:26:08 +00001646 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 +00001647 else if (type_found == T_NSEC3)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001648 return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001649 else
1650 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001651}
Simon Kelley9a31b682015-12-15 10:20:39 +00001652
1653/* Check signing status of name.
1654 returns:
Simon Kelley3b799c82015-12-17 16:58:04 +00001655 STAT_SECURE zone is signed.
1656 STAT_INSECURE zone proved unsigned.
1657 STAT_NEED_DS require DS record of name returned in keyname.
1658 STAT_NEED_KEY require DNSKEY record of name returned in keyname.
Simon Kelley9a31b682015-12-15 10:20:39 +00001659 name returned unaltered.
1660*/
1661static int zone_status(char *name, int class, char *keyname, time_t now)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001662{
Simon Kelleya63b8b82016-01-12 11:28:58 +00001663 int name_start = strlen(name); /* for when TA is root */
Simon Kelley9a31b682015-12-15 10:20:39 +00001664 struct crec *crecp;
1665 char *p;
Simon Kelleya63b8b82016-01-12 11:28:58 +00001666
1667 /* First, work towards the root, looking for a trust anchor.
1668 This can either be one configured, or one previously cached.
1669 We can assume, if we don't find one first, that there is
1670 a trust anchor at the root. */
1671 for (p = name; p; p = strchr(p, '.'))
1672 {
1673 if (*p == '.')
1674 p++;
1675
1676 if (cache_find_by_name(NULL, p, now, F_DS))
1677 {
1678 name_start = p - name;
1679 break;
1680 }
1681 }
Simon Kelley367341f2016-01-12 15:58:23 +00001682
Simon Kelleya63b8b82016-01-12 11:28:58 +00001683 /* Now work away from the trust anchor */
Simon Kelley9a31b682015-12-15 10:20:39 +00001684 while (1)
1685 {
1686 strcpy(keyname, &name[name_start]);
1687
1688 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
1689 return STAT_NEED_DS;
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001690
Josh Soref730c6742017-02-06 16:14:04 +00001691 /* F_DNSSECOK misused in DS cache records to non-existence of NS record.
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001692 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
1693 but that's because there's no NS record either, ie this isn't the start
1694 of a zone. We only prove that the DNS tree below a node is unsigned when
1695 we prove that we're at a zone cut AND there's no DS record. */
1696 if (crecp->flags & F_NEG)
1697 {
1698 if (crecp->flags & F_DNSSECOK)
1699 return STAT_INSECURE; /* proved no DS here */
1700 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001701 else
Simon Kelley2dbba342015-12-16 13:41:58 +00001702 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001703 /* If all the DS records have digest and/or sig algos we don't support,
1704 then the zone is insecure. Note that if an algo
1705 appears in the DS, then RRSIGs for that algo MUST
1706 exist for each RRset: 4035 para 2.2 So if we find
1707 a DS here with digest and sig we can do, we're entitled
1708 to assume we can validate the zone and if we can't later,
1709 because an RRSIG is missing we return BOGUS.
1710 */
Simon Kelley2dbba342015-12-16 13:41:58 +00001711 do
1712 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001713 if (crecp->uid == (unsigned int)class &&
Simon Kelleyb77efc12017-10-27 23:23:53 +01001714 ds_digest_name(crecp->addr.ds.digest) &&
1715 algo_digest_name(crecp->addr.ds.algo))
Simon Kelleya86fdf42015-12-20 21:19:20 +00001716 break;
Simon Kelley2dbba342015-12-16 13:41:58 +00001717 }
1718 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
Simon Kelley2dbba342015-12-16 13:41:58 +00001719
Simon Kelleya86fdf42015-12-20 21:19:20 +00001720 if (!crecp)
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001721 return STAT_INSECURE;
Simon Kelley2dbba342015-12-16 13:41:58 +00001722 }
1723
Simon Kelley9a31b682015-12-15 10:20:39 +00001724 if (name_start == 0)
1725 break;
1726
1727 for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
1728
1729 if (p != name)
1730 p++;
1731
1732 name_start = p - name;
1733 }
1734
1735 return STAT_SECURE;
1736}
1737
1738/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3)
1739 Return code:
1740 STAT_SECURE if it validates.
1741 STAT_INSECURE at least one RRset not validated, because in unsigned zone.
1742 STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
1743 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
Simon Kelleya6004d72017-10-25 17:48:19 +01001744 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
1745
Simon Kelley373e9172017-12-01 22:40:56 +00001746 daemon->rr_status points to a char array which corressponds to the RRs in the
Simon Kelleya6004d72017-10-25 17:48:19 +01001747 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 +00001748*/
1749int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
Simon Kelley373e9172017-12-01 22:40:56 +00001750 int *class, int check_unsigned, int *neganswer, int *nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001751{
1752 static unsigned char **targets = NULL;
1753 static int target_sz = 0;
1754
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001755 unsigned char *ans_start, *p1, *p2;
Simon Kelleya6004d72017-10-25 17:48:19 +01001756 int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
Simon Kelley91421cb2018-10-18 19:21:55 +01001757 int i, j, rc = STAT_INSECURE;
Simon Kelleya6004d72017-10-25 17:48:19 +01001758 int secure = STAT_SECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001759
Simon Kelley373e9172017-12-01 22:40:56 +00001760 /* extend rr_status if necessary */
1761 if (daemon->rr_status_sz < ntohs(header->ancount))
1762 {
1763 char *new = whine_malloc(ntohs(header->ancount) + 64);
1764
1765 if (!new)
1766 return STAT_BOGUS;
1767
1768 free(daemon->rr_status);
1769 daemon->rr_status = new;
1770 daemon->rr_status_sz = ntohs(header->ancount) + 64;
1771 }
1772
1773 memset(daemon->rr_status, 0, ntohs(header->ancount));
Simon Kelleya6004d72017-10-25 17:48:19 +01001774
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001775 if (neganswer)
1776 *neganswer = 0;
1777
Simon Kelley87070192014-03-01 20:48:24 +00001778 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001779 return STAT_BOGUS;
1780
Simon Kelley87070192014-03-01 20:48:24 +00001781 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001782 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001783
Simon Kelley9a31b682015-12-15 10:20:39 +00001784 p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001785
Simon Kelley9a31b682015-12-15 10:20:39 +00001786 /* Find all the targets we're looking for answers to.
1787 The zeroth array element is for the query, subsequent ones
1788 for CNAME targets, unless the query is for a CNAME. */
1789
1790 if (!expand_workspace(&targets, &target_sz, 0))
1791 return STAT_BOGUS;
1792
1793 targets[0] = p1;
1794 targetidx = 1;
1795
Simon Kelley394ff492015-03-29 22:17:14 +01001796 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001797 return STAT_BOGUS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001798
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001799 GETSHORT(qtype, p1);
1800 GETSHORT(qclass, p1);
1801 ans_start = p1;
1802
Simon Kelley9a31b682015-12-15 10:20:39 +00001803 /* Can't validate an RRSIG query */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001804 if (qtype == T_RRSIG)
1805 return STAT_INSECURE;
Simon Kelleye3ec6f02015-06-12 21:39:11 +01001806
Simon Kelley9a31b682015-12-15 10:20:39 +00001807 if (qtype != T_CNAME)
1808 for (j = ntohs(header->ancount); j != 0; j--)
1809 {
1810 if (!(p1 = skip_name(p1, header, plen, 10)))
1811 return STAT_BOGUS; /* bad packet */
1812
1813 GETSHORT(type2, p1);
1814 p1 += 6; /* class, TTL */
1815 GETSHORT(rdlen2, p1);
1816
1817 if (type2 == T_CNAME)
1818 {
1819 if (!expand_workspace(&targets, &target_sz, targetidx))
1820 return STAT_BOGUS;
1821
1822 targets[targetidx++] = p1; /* pointer to target name */
1823 }
1824
1825 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1826 return STAT_BOGUS;
1827 }
1828
Simon Kelley0fc2f312014-01-08 10:26:58 +00001829 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001830 {
Simon Kelley91421cb2018-10-18 19:21:55 +01001831 if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
1832 return STAT_BOGUS;
1833
1834 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001835 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001836
1837 GETSHORT(type1, p1);
1838 GETSHORT(class1, p1);
1839 p1 += 4; /* TTL */
1840 GETSHORT(rdlen1, p1);
1841
1842 /* Don't try and validate RRSIGs! */
Simon Kelleya6004d72017-10-25 17:48:19 +01001843 if (type1 == T_RRSIG)
1844 continue;
1845
1846 /* Check if we've done this RRset already */
1847 for (p2 = ans_start, j = 0; j < i; j++)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001848 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001849 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1850 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001851
Simon Kelleya6004d72017-10-25 17:48:19 +01001852 GETSHORT(type2, p2);
1853 GETSHORT(class2, p2);
1854 p2 += 4; /* TTL */
1855 GETSHORT(rdlen2, p2);
1856
1857 if (type2 == type1 && class2 == class1 && rc == 1)
1858 break; /* Done it before: name, type, class all match. */
1859
1860 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1861 return STAT_BOGUS;
1862 }
1863
1864 if (j != i)
1865 {
1866 /* Done already: copy the validation status */
Simon Kelley373e9172017-12-01 22:40:56 +00001867 if (i < ntohs(header->ancount))
1868 daemon->rr_status[i] = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +01001869 }
1870 else
1871 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001872 /* Not done, validate now */
Simon Kelleya6004d72017-10-25 17:48:19 +01001873 int sigcnt, rrcnt;
1874 char *wildname;
1875
1876 if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
1877 return STAT_BOGUS;
1878
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001879 /* 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 +01001880 if (sigcnt == 0)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001881 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001882 if (check_unsigned)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001883 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001884 rc = zone_status(name, class1, keyname, now);
1885 if (rc == STAT_SECURE)
1886 rc = STAT_BOGUS;
1887 if (class)
1888 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001889 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001890 else
1891 rc = STAT_INSECURE;
Simon Kelley5107ace2014-02-23 10:48:32 +00001892
Simon Kelleya6004d72017-10-25 17:48:19 +01001893 if (rc != STAT_INSECURE)
1894 return rc;
1895 }
1896 else
1897 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001898 /* explore_rrset() gives us key name from sigs in keyname.
1899 Can't overwrite name here. */
1900 strcpy(daemon->workspacename, keyname);
1901 rc = zone_status(daemon->workspacename, class1, keyname, now);
Simon Kelleya6004d72017-10-25 17:48:19 +01001902
1903 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001904 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001905 if (class)
Simon Kelley3b799c82015-12-17 16:58:04 +00001906 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley9a31b682015-12-15 10:20:39 +00001907 return rc;
Simon Kelleya6004d72017-10-25 17:48:19 +01001908 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001909
Simon Kelleya6004d72017-10-25 17:48:19 +01001910 /* Zone is insecure, don't need to validate RRset */
1911 if (rc == STAT_SECURE)
Simon Kelley9a31b682015-12-15 10:20:39 +00001912 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001913 rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
1914 rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
1915
1916 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
1917 {
1918 if (class)
1919 *class = class1; /* Class for DS or DNSKEY */
1920 return rc;
1921 }
1922
Simon Kelley9a31b682015-12-15 10:20:39 +00001923 /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
Simon Kelleya6004d72017-10-25 17:48:19 +01001924
1925 /* Note that RR is validated */
Simon Kelley373e9172017-12-01 22:40:56 +00001926 if (i < ntohs(header->ancount))
1927 daemon->rr_status[i] = 1;
Simon Kelleya6004d72017-10-25 17:48:19 +01001928
Simon Kelley9a31b682015-12-15 10:20:39 +00001929 /* Note if we've validated either the answer to the question
1930 or the target of a CNAME. Any not noted will need NSEC or
1931 to be in unsigned space. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001932 for (j = 0; j <targetidx; j++)
1933 if ((p2 = targets[j]))
1934 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001935 int rc1;
1936 if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001937 return STAT_BOGUS; /* bad packet */
1938
Simon Kelleya6004d72017-10-25 17:48:19 +01001939 if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
Simon Kelley9a31b682015-12-15 10:20:39 +00001940 targets[j] = NULL;
1941 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001942
1943 /* An attacker replay a wildcard answer with a different
1944 answer and overlay a genuine RR. To prove this
1945 hasn't happened, the answer must prove that
1946 the genuine record doesn't exist. Check that here.
1947 Note that we may not yet have validated the NSEC/NSEC3 RRsets.
1948 That's not a problem since if the RRsets later fail
1949 we'll return BOGUS then. */
1950 if (rc == STAT_SECURE_WILDCARD &&
1951 !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001952 return STAT_BOGUS;
Simon Kelleya6004d72017-10-25 17:48:19 +01001953
1954 rc = STAT_SECURE;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001955 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001956 }
1957 }
1958
Simon Kelleya6004d72017-10-25 17:48:19 +01001959 if (rc == STAT_INSECURE)
1960 secure = STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001961 }
1962
Simon Kelley9a31b682015-12-15 10:20:39 +00001963 /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
Simon Kelley7f008432018-04-15 20:01:49 +01001964 if (secure == STAT_SECURE)
Simon Kelley4e72fec2018-04-11 22:49:31 +01001965 for (j = 0; j <targetidx; j++)
1966 if ((p2 = targets[j]))
1967 {
1968 if (neganswer)
1969 *neganswer = 1;
1970
1971 if (!extract_name(header, plen, &p2, name, 1, 10))
1972 return STAT_BOGUS; /* bad packet */
1973
1974 /* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
1975
1976 /* For anything other than a DS record, this situation is OK if either
1977 the answer is in an unsigned zone, or there's a NSEC records. */
1978 if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
1979 {
1980 /* Empty DS without NSECS */
1981 if (qtype == T_DS)
1982 return STAT_BOGUS;
1983
1984 if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
1985 {
1986 if (class)
1987 *class = qclass; /* Class for NEED_DS or NEED_KEY */
1988 return rc;
1989 }
1990
1991 return STAT_BOGUS; /* signed zone, no NSECs */
1992 }
1993 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001994
Simon Kelleya6004d72017-10-25 17:48:19 +01001995 return secure;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001996}
1997
1998
Giovanni Bajo3471f182012-04-25 17:49:16 +02001999/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002000int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02002001{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002002 if (alg == 1)
2003 {
2004 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
2005 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002006 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002007 }
2008 else
2009 {
Simon Kelley1633e302014-02-10 16:42:46 +00002010 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002011 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002012
Simon Kelley0fc2f312014-01-08 10:26:58 +00002013 for (i = 0; i < keylen; ++i)
2014 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002015
Simon Kelley0fc2f312014-01-08 10:26:58 +00002016 ac += (ac >> 16) & 0xffff;
2017 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002018 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002019}
2020
Simon Kelley33702ab2015-12-28 23:17:15 +00002021size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
Simon Kelleye1791f32018-10-06 23:23:23 +01002022 int type, int edns_pktsz)
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002023{
2024 unsigned char *p;
Simon Kelleya77cec82015-05-08 16:25:38 +01002025 size_t ret;
Giovanni Bajo0304d282012-05-02 03:29:52 +02002026
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002027 header->qdcount = htons(1);
2028 header->ancount = htons(0);
2029 header->nscount = htons(0);
2030 header->arcount = htons(0);
2031
2032 header->hb3 = HB3_RD;
2033 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002034 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2035 this allows it to select auth servers when one is returning bad data. */
2036 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002037
2038 /* ID filled in later */
2039
2040 p = (unsigned char *)(header+1);
2041
Simon Kelley0549c732017-09-25 18:17:11 +01002042 p = do_rfc1035_name(p, name, NULL);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002043 *p++ = 0;
2044 PUTSHORT(type, p);
2045 PUTSHORT(class, p);
2046
Simon Kelleya77cec82015-05-08 16:25:38 +01002047 ret = add_do_bit(header, p - (unsigned char *)header, end);
2048
Simon Kelley5bb88f02015-12-21 16:23:47 +00002049 if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
Simon Kelleya77cec82015-05-08 16:25:38 +01002050 PUTSHORT(edns_pktsz, p);
2051
2052 return ret;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002053}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002054
2055unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2056{
2057 int q;
2058 unsigned int len;
2059 unsigned char *p = (unsigned char *)(header+1);
2060 const struct nettle_hash *hash;
2061 void *ctx;
2062 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002063
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002064 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2065 return NULL;
2066
2067 for (q = ntohs(header->qdcount); q != 0; q--)
2068 {
Simon Kelley394ff492015-03-29 22:17:14 +01002069 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002070 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002071
2072 len = to_wire(name);
2073 hash->update(ctx, len, (unsigned char *)name);
2074 /* CRC the class and type as well */
2075 hash->update(ctx, 4, p);
2076
2077 p += 4;
2078 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002079 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002080 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002081
2082 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002083 return digest;
2084}
2085
Simon Kelley0fc2f312014-01-08 10:26:58 +00002086#endif /* HAVE_DNSSEC */