blob: 8ff7a73fe5065d45867ce79ceafbded11f89eced [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
801 /* Cache needs to known class for DNSSEC stuff */
802 a.addr.dnssec.class = class;
803
804 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
805 {
806 if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
Simon Kelley93be5b12015-12-15 12:04:40 +0000807 {
808 blockdata_free(key);
809 return STAT_BOGUS;
810 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000811 else
812 {
Simon Kelley15379ea2015-12-21 18:31:55 +0000813 a.addr.log.keytag = keytag;
814 a.addr.log.algo = algo;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100815 if (algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000816 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000817 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000818 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
Simon Kelley8d718cb2014-02-03 16:27:37 +0000819
820 recp1->addr.key.keylen = rdlen - 4;
821 recp1->addr.key.keydata = key;
822 recp1->addr.key.algo = algo;
823 recp1->addr.key.keytag = keytag;
824 recp1->addr.key.flags = flags;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000825 }
826 }
827 }
Simon Kelley93be5b12015-12-15 12:04:40 +0000828
Simon Kelley8d718cb2014-02-03 16:27:37 +0000829 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000830 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000831
Simon Kelleye7829ae2014-01-22 22:21:51 +0000832 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000833 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000834 }
835
Simon Kelley0fc2f312014-01-08 10:26:58 +0000836 /* commit cache insert. */
837 cache_end_insert();
Simon Kelley9a31b682015-12-15 10:20:39 +0000838 return STAT_OK;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000839 }
840
Simon Kelley25cf5e32015-01-09 15:53:03 +0000841 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
Simon Kelley0fc2f312014-01-08 10:26:58 +0000842 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000843}
Simon Kelley0fc2f312014-01-08 10:26:58 +0000844
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000845/* The DNS packet is expected to contain the answer to a DS query
846 Put all DSs in the answer which are valid into the cache.
Simon Kelley9a31b682015-12-15 10:20:39 +0000847 Also handles replies which prove that there's no DS at this location,
848 either because the zone is unsigned or this isn't a zone cut. These are
849 cached too.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000850 return codes:
Simon Kelley9a31b682015-12-15 10:20:39 +0000851 STAT_OK At least one valid DS found and in cache.
Simon Kelley97e618a2015-01-07 21:55:43 +0000852 STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000853 STAT_NEED_KEY DNSKEY records to validate a DS not found, name in keyname
Simon Kelley9a31b682015-12-15 10:20:39 +0000854 STAT_NEED_DS DS record needed.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000855*/
856
857int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
858{
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000859 unsigned char *p = (unsigned char *)(header+1);
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000860 int qtype, qclass, rc, i, neganswer, nons;
861 int aclass, atype, rdlen;
862 unsigned long ttl;
863 struct all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000864
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000865 if (ntohs(header->qdcount) != 1 ||
Simon Kelleyb8eac192014-02-27 14:30:03 +0000866 !(p = skip_name(p, header, plen, 4)))
Simon Kelley87070192014-03-01 20:48:24 +0000867 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000868
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000869 GETSHORT(qtype, p);
870 GETSHORT(qclass, p);
871
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000872 if (qtype != T_DS || qclass != class)
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000873 rc = STAT_BOGUS;
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000874 else
Simon Kelley4e72fec2018-04-11 22:49:31 +0100875 rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 1, &neganswer, &nons);
Simon Kelley97e618a2015-01-07 21:55:43 +0000876
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000877 if (rc == STAT_INSECURE)
878 rc = STAT_BOGUS;
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
927 /* Cache needs to known class for DNSSEC stuff */
928 a.addr.dnssec.class = class;
929
930 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
931 {
932 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
933 {
934 blockdata_free(key);
935 return STAT_BOGUS;
936 }
937 else
938 {
Simon Kelley15379ea2015-12-21 18:31:55 +0000939 a.addr.log.keytag = keytag;
940 a.addr.log.algo = algo;
941 a.addr.log.digest = digest;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100942 if (ds_digest_name(digest) && algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000943 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000944 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000945 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000946
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000947 crecp->addr.ds.digest = digest;
948 crecp->addr.ds.keydata = key;
949 crecp->addr.ds.algo = algo;
950 crecp->addr.ds.keytag = keytag;
951 crecp->addr.ds.keylen = rdlen - 4;
952 }
953 }
954
955 p = psave;
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000956 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000957 if (!ADD_RDLEN(header, p, plen, rdlen))
958 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000959 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000960
961 cache_end_insert();
962
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000963 }
964 else
965 {
966 int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
967 unsigned long minttl = ULONG_MAX;
968
969 if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
970 return STAT_BOGUS;
971
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000972 if (RCODE(header) == NXDOMAIN)
973 flags |= F_NXDOMAIN;
974
Simon Kelley97e618a2015-01-07 21:55:43 +0000975 /* We only cache validated DS records, DNSSECOK flag hijacked
976 to store presence/absence of NS. */
977 if (nons)
978 flags &= ~F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000979
980 for (i = ntohs(header->nscount); i != 0; i--)
981 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000982 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +0000983 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000984
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000985 GETSHORT(atype, p);
986 GETSHORT(aclass, p);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000987 GETLONG(ttl, p);
988 GETSHORT(rdlen, p);
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000989
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000990 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000991 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000992
993 if (aclass != class || atype != T_SOA)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000994 {
995 p += rdlen;
996 continue;
997 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000998
Simon Kelleyb8eac192014-02-27 14:30:03 +0000999 if (ttl < minttl)
1000 minttl = ttl;
1001
1002 /* MNAME */
1003 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001004 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001005 /* RNAME */
1006 if (!(p = skip_name(p, header, plen, 20)))
Simon Kelley87070192014-03-01 20:48:24 +00001007 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001008 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
1009
1010 GETLONG(ttl, p); /* minTTL */
1011 if (ttl < minttl)
1012 minttl = ttl;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001013
1014 break;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001015 }
1016
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001017 if (i != 0)
1018 {
1019 cache_start_insert();
1020
1021 a.addr.dnssec.class = class;
Simon Kelley93be5b12015-12-15 12:04:40 +00001022 if (!cache_insert(name, &a, now, ttl, flags))
1023 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001024
Simon Kelley97e618a2015-01-07 21:55:43 +00001025 cache_end_insert();
1026
Simon Kelley9a31b682015-12-15 10:20:39 +00001027 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001028 }
Simon Kelleyb8eac192014-02-27 14:30:03 +00001029 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001030
Simon Kelley9a31b682015-12-15 10:20:39 +00001031 return STAT_OK;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001032}
1033
Simon Kelley9a31b682015-12-15 10:20:39 +00001034
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001035/* 4034 6.1 */
1036static int hostname_cmp(const char *a, const char *b)
1037{
Simon Kelleydbf72122014-01-21 14:28:02 +00001038 char *sa, *ea, *ca, *sb, *eb, *cb;
1039 unsigned char ac, bc;
1040
1041 sa = ea = (char *)a + strlen(a);
1042 sb = eb = (char *)b + strlen(b);
1043
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001044 while (1)
1045 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001046 while (sa != a && *(sa-1) != '.')
1047 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001048
Simon Kelleydbf72122014-01-21 14:28:02 +00001049 while (sb != b && *(sb-1) != '.')
1050 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001051
Simon Kelleydbf72122014-01-21 14:28:02 +00001052 ca = sa;
1053 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001054
Simon Kelleydbf72122014-01-21 14:28:02 +00001055 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001056 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001057 if (ca == ea)
1058 {
1059 if (cb == eb)
1060 break;
1061
1062 return -1;
1063 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001064
Simon Kelleydbf72122014-01-21 14:28:02 +00001065 if (cb == eb)
1066 return 1;
1067
1068 ac = (unsigned char) *ca++;
1069 bc = (unsigned char) *cb++;
1070
1071 if (ac >= 'A' && ac <= 'Z')
1072 ac += 'a' - 'A';
1073 if (bc >= 'A' && bc <= 'Z')
1074 bc += 'a' - 'A';
1075
Simon Kelley979cdf92014-01-21 16:26:41 +00001076 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001077 return -1;
1078 else if (ac != bc)
1079 return 1;
1080 }
1081
1082
1083 if (sa == a)
1084 {
1085 if (sb == b)
1086 return 0;
1087
1088 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001089 }
1090
Simon Kelleydbf72122014-01-21 14:28:02 +00001091 if (sb == b)
1092 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001093
Simon Kelley3e86d312015-12-20 20:50:05 +00001094 ea = --sa;
1095 eb = --sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001096 }
1097}
1098
Simon Kelley4fe67442018-01-19 12:26:08 +00001099static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
1100 char *workspace1_in, char *workspace2, char *name, int type, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001101{
1102 int i, rc, rdlen;
1103 unsigned char *p, *psave;
1104 int offset = (type & 0xff) >> 3;
1105 int mask = 0x80 >> (type & 0x07);
Simon Kelley97e618a2015-01-07 21:55:43 +00001106
1107 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001108 *nons = 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001109
1110 /* Find NSEC record that proves name doesn't exist */
1111 for (i = 0; i < nsec_count; i++)
1112 {
Simon Kelley4fe67442018-01-19 12:26:08 +00001113 char *workspace1 = workspace1_in;
1114 int sig_labels, name_labels;
1115
Simon Kelley5107ace2014-02-23 10:48:32 +00001116 p = nsecs[i];
Simon Kelley394ff492015-03-29 22:17:14 +01001117 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001118 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001119 p += 8; /* class, type, TTL */
1120 GETSHORT(rdlen, p);
1121 psave = p;
Simon Kelley394ff492015-03-29 22:17:14 +01001122 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001123 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001124
1125 /* If NSEC comes from wildcard expansion, use original wildcard
1126 as name for computation. */
1127 sig_labels = *labels[i];
1128 name_labels = count_labels(workspace1);
1129
1130 if (sig_labels < name_labels)
1131 {
1132 int k;
1133 for (k = name_labels - sig_labels; k != 0; k--)
1134 {
1135 while (*workspace1 != '.' && *workspace1 != 0)
1136 workspace1++;
1137 if (k != 1 && *workspace1 == '.')
1138 workspace1++;
1139 }
1140
1141 workspace1--;
1142 *workspace1 = '*';
1143 }
1144
Simon Kelley5107ace2014-02-23 10:48:32 +00001145 rc = hostname_cmp(workspace1, name);
1146
1147 if (rc == 0)
1148 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001149 /* 4035 para 5.4. Last sentence */
1150 if (type == T_NSEC || type == T_RRSIG)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001151 return 1;
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001152
Simon Kelley5107ace2014-02-23 10:48:32 +00001153 /* NSEC with the same name as the RR we're testing, check
1154 that the type in question doesn't appear in the type map */
1155 rdlen -= p - psave;
1156 /* rdlen is now length of type map, and p points to it */
1157
Simon Kelley97e618a2015-01-07 21:55:43 +00001158 /* If we can prove that there's no NS record, return that information. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001159 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
1160 *nons = 0;
Simon Kelley97e618a2015-01-07 21:55:43 +00001161
Simon Kelley9a31b682015-12-15 10:20:39 +00001162 if (rdlen >= 2 && p[0] == 0)
1163 {
1164 /* A CNAME answer would also be valid, so if there's a CNAME is should
1165 have been returned. */
1166 if ((p[2] & (0x80 >> T_CNAME)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001167 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001168
1169 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001170 DS from the wrong side of the delegation. For the root DS,
1171 this is expected. */
1172 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001173 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001174 }
1175
Simon Kelley5107ace2014-02-23 10:48:32 +00001176 while (rdlen >= 2)
1177 {
1178 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001179 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001180
1181 if (p[0] == type >> 8)
1182 {
1183 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001184 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001185 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001186
Josh Soref730c6742017-02-06 16:14:04 +00001187 break; /* finished checking */
Simon Kelley5107ace2014-02-23 10:48:32 +00001188 }
1189
1190 rdlen -= p[1];
1191 p += p[1];
1192 }
1193
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001194 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001195 }
1196 else if (rc == -1)
1197 {
1198 /* Normal case, name falls between NSEC name and next domain name,
1199 wrap around case, name falls between NSEC name (rc == -1) and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001200 if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001201 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001202 }
1203 else
1204 {
1205 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001206 if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001207 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001208 }
1209 }
1210
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001211 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001212}
1213
1214/* return digest length, or zero on error */
1215static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1216 unsigned char *salt, int salt_len, int iterations)
1217{
1218 void *ctx;
1219 unsigned char *digest;
1220 int i;
1221
1222 if (!hash_init(hash, &ctx, &digest))
1223 return 0;
1224
1225 hash->update(ctx, to_wire(in), (unsigned char *)in);
1226 hash->update(ctx, salt_len, salt);
1227 hash->digest(ctx, hash->digest_size, digest);
1228
1229 for(i = 0; i < iterations; i++)
1230 {
1231 hash->update(ctx, hash->digest_size, digest);
1232 hash->update(ctx, salt_len, salt);
1233 hash->digest(ctx, hash->digest_size, digest);
1234 }
1235
1236 from_wire(in);
1237
1238 *out = digest;
1239 return hash->digest_size;
1240}
1241
1242/* Decode base32 to first "." or end of string */
1243static int base32_decode(char *in, unsigned char *out)
1244{
Simon Kelleya857daa2014-02-24 21:01:09 +00001245 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001246 unsigned char *p = out;
1247
Simon Kelleya857daa2014-02-24 21:01:09 +00001248 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001249 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001250 if (c >= '0' && c <= '9')
1251 c -= '0';
1252 else if (c >= 'a' && c <= 'v')
1253 c -= 'a', c += 10;
1254 else if (c >= 'A' && c <= 'V')
1255 c -= 'A', c += 10;
1256 else
1257 return 0;
1258
1259 for (mask = 0x10, i = 0; i < 5; i++)
1260 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001261 if (c & mask)
1262 oc |= 1;
1263 mask = mask >> 1;
1264 if (((++on) & 7) == 0)
1265 *p++ = oc;
1266 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001267 }
1268 }
1269
1270 if ((on & 7) != 0)
1271 return 0;
1272
1273 return p - out;
1274}
1275
Simon Kelleyfbc52052014-12-23 15:46:08 +00001276static 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 +00001277 char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001278{
Simon Kelley9a31b682015-12-15 10:20:39 +00001279 int i, hash_len, salt_len, base32_len, rdlen, flags;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001280 unsigned char *p, *psave;
1281
1282 for (i = 0; i < nsec_count; i++)
1283 if ((p = nsecs[i]))
1284 {
Simon Kelley394ff492015-03-29 22:17:14 +01001285 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleyfbc52052014-12-23 15:46:08 +00001286 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
1287 return 0;
1288
1289 p += 8; /* class, type, TTL */
1290 GETSHORT(rdlen, p);
1291 psave = p;
Simon Kelley9a31b682015-12-15 10:20:39 +00001292 p++; /* algo */
1293 flags = *p++; /* flags */
1294 p += 2; /* iterations */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001295 salt_len = *p++; /* salt_len */
1296 p += salt_len; /* salt */
1297 hash_len = *p++; /* p now points to next hashed name */
1298
1299 if (!CHECK_LEN(header, p, plen, hash_len))
1300 return 0;
1301
1302 if (digest_len == base32_len && hash_len == base32_len)
1303 {
1304 int rc = memcmp(workspace2, digest, digest_len);
1305
1306 if (rc == 0)
1307 {
1308 /* We found an NSEC3 whose hashed name exactly matches the query, so
1309 we just need to check the type map. p points to the RR data for the record. */
1310
1311 int offset = (type & 0xff) >> 3;
1312 int mask = 0x80 >> (type & 0x07);
1313
1314 p += hash_len; /* skip next-domain hash */
1315 rdlen -= p - psave;
1316
1317 if (!CHECK_LEN(header, p, plen, rdlen))
1318 return 0;
1319
Simon Kelley9a31b682015-12-15 10:20:39 +00001320 if (rdlen >= 2 && p[0] == 0)
1321 {
Simon Kelleyec0628c2015-12-31 20:55:39 +00001322 /* If we can prove that there's no NS record, return that information. */
1323 if (nons && (p[2] & (0x80 >> T_NS)) != 0)
1324 *nons = 0;
1325
Simon Kelley9a31b682015-12-15 10:20:39 +00001326 /* A CNAME answer would also be valid, so if there's a CNAME is should
1327 have been returned. */
1328 if ((p[2] & (0x80 >> T_CNAME)) != 0)
1329 return 0;
1330
1331 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001332 DS from the wrong side of the delegation. For the root DS,
1333 this is expected. */
1334 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001335 return 0;
1336 }
1337
Simon Kelleyfbc52052014-12-23 15:46:08 +00001338 while (rdlen >= 2)
1339 {
1340 if (p[0] == type >> 8)
1341 {
1342 /* Does the NSEC3 say our type exists? */
1343 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001344 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001345
Josh Soref730c6742017-02-06 16:14:04 +00001346 break; /* finished checking */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001347 }
1348
1349 rdlen -= p[1];
1350 p += p[1];
1351 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001352
Simon Kelleyfbc52052014-12-23 15:46:08 +00001353 return 1;
1354 }
Simon Kelley4d25cf82015-06-06 23:13:57 +01001355 else if (rc < 0)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001356 {
1357 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1358 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001359 if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001360 {
1361 if ((flags & 0x01) && nons) /* opt out */
1362 *nons = 0;
1363
1364 return 1;
1365 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001366 }
1367 else
1368 {
1369 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001370 if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001371 {
1372 if ((flags & 0x01) && nons) /* opt out */
1373 *nons = 0;
1374
1375 return 1;
1376 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001377 }
1378 }
1379 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001380
Simon Kelleyfbc52052014-12-23 15:46:08 +00001381 return 0;
1382}
1383
Simon Kelley24187532014-02-24 21:46:44 +00001384static 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 +00001385 char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001386{
Simon Kelleya857daa2014-02-24 21:01:09 +00001387 unsigned char *salt, *p, *digest;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001388 int digest_len, i, iterations, salt_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001389 struct nettle_hash const *hash;
1390 char *closest_encloser, *next_closest, *wildcard;
Simon Kelley97e618a2015-01-07 21:55:43 +00001391
1392 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001393 *nons = 1;
Simon Kelley97e618a2015-01-07 21:55:43 +00001394
Simon Kelley5107ace2014-02-23 10:48:32 +00001395 /* Look though the NSEC3 records to find the first one with
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001396 an algorithm we support.
Simon Kelley5107ace2014-02-23 10:48:32 +00001397
1398 Take the algo, iterations, and salt of that record
1399 as the ones we're going to use, and prune any
1400 that don't match. */
1401
1402 for (i = 0; i < nsec_count; i++)
1403 {
1404 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001405 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001406
1407 p += 10; /* type, class, TTL, rdlen */
1408 algo = *p++;
1409
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001410 if ((hash = hash_find(nsec3_digest_name(algo))))
Simon Kelley5107ace2014-02-23 10:48:32 +00001411 break; /* known algo */
1412 }
1413
1414 /* No usable NSEC3s */
1415 if (i == nsec_count)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001416 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001417
1418 p++; /* flags */
Simon Kelley40205a02016-03-14 21:24:00 +00001419
Simon Kelley5107ace2014-02-23 10:48:32 +00001420 GETSHORT (iterations, p);
Simon Kelley40205a02016-03-14 21:24:00 +00001421 /* Upper-bound iterations, to avoid DoS.
1422 Strictly, there are lower bounds for small keys, but
1423 since we don't have key size info here, at least limit
1424 to the largest bound, for 4096-bit keys. RFC 5155 10.3 */
1425 if (iterations > 2500)
1426 return 0;
1427
Simon Kelley5107ace2014-02-23 10:48:32 +00001428 salt_len = *p++;
1429 salt = p;
1430 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001431 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001432
1433 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1434 for (i = 0; i < nsec_count; i++)
1435 {
1436 unsigned char *nsec3p = nsecs[i];
Simon Kelleyce5732e2015-12-20 21:39:19 +00001437 int this_iter, flags;
Simon Kelley5107ace2014-02-23 10:48:32 +00001438
1439 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1440
1441 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001442 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001443
1444 p += 10; /* type, class, TTL, rdlen */
1445
1446 if (*p++ != algo)
1447 continue;
1448
Simon Kelleyce5732e2015-12-20 21:39:19 +00001449 flags = *p++; /* flags */
Simon Kelley5107ace2014-02-23 10:48:32 +00001450
Simon Kelleyce5732e2015-12-20 21:39:19 +00001451 /* 5155 8.2 */
1452 if (flags != 0 && flags != 1)
1453 continue;
1454
Simon Kelleya857daa2014-02-24 21:01:09 +00001455 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001456 if (this_iter != iterations)
1457 continue;
1458
1459 if (salt_len != *p++)
1460 continue;
1461
1462 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001463 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001464
1465 if (memcmp(p, salt, salt_len) != 0)
1466 continue;
1467
1468 /* All match, put the pointer back */
1469 nsecs[i] = nsec3p;
1470 }
1471
Simon Kelleyfbc52052014-12-23 15:46:08 +00001472 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001473 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001474
Simon Kelleya969ba62018-01-20 23:08:38 +00001475 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 +00001476 return 1;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001477
1478 /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
1479 or an answer inferred from a wildcard record. */
Simon Kelley5107ace2014-02-23 10:48:32 +00001480 closest_encloser = name;
1481 next_closest = NULL;
1482
1483 do
1484 {
1485 if (*closest_encloser == '.')
1486 closest_encloser++;
1487
Simon Kelleyfbc52052014-12-23 15:46:08 +00001488 if (wildname && hostname_isequal(closest_encloser, wildname))
1489 break;
1490
Simon Kelleya857daa2014-02-24 21:01:09 +00001491 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001492 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001493
1494 for (i = 0; i < nsec_count; i++)
1495 if ((p = nsecs[i]))
1496 {
Simon Kelley394ff492015-03-29 22:17:14 +01001497 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001498 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001499 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001500
Simon Kelleya857daa2014-02-24 21:01:09 +00001501 if (digest_len == base32_len &&
1502 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001503 break; /* Gotit */
1504 }
1505
1506 if (i != nsec_count)
1507 break;
1508
1509 next_closest = closest_encloser;
1510 }
1511 while ((closest_encloser = strchr(closest_encloser, '.')));
1512
Simon Kelleya7b27e82016-03-16 19:11:52 +00001513 if (!closest_encloser || !next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001514 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001515
Simon Kelley24187532014-02-24 21:46:44 +00001516 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001517 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001518 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001519
Simon Kelleya969ba62018-01-20 23:08:38 +00001520 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001521 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001522
1523 /* Finally, check that there's no seat of wildcard synthesis */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001524 if (!wildname)
1525 {
1526 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001527 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001528
1529 wildcard--;
1530 *wildcard = '*';
1531
1532 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001533 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001534
Simon Kelleya969ba62018-01-20 23:08:38 +00001535 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001536 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001537 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001538
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001539 return 1;
1540}
1541
1542static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
1543{
Simon Kelley4fe67442018-01-19 12:26:08 +00001544 static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
1545 static int nsecset_sz = 0, rrsig_labels_sz = 0;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001546
1547 int type_found = 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001548 unsigned char *auth_start, *p = skip_questions(header, plen);
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001549 int type, class, rdlen, i, nsecs_found;
1550
1551 /* Move to NS section */
1552 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1553 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001554
1555 auth_start = p;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001556
1557 for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
1558 {
1559 unsigned char *pstart = p;
1560
Simon Kelley4fe67442018-01-19 12:26:08 +00001561 if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001562 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001563
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001564 GETSHORT(type, p);
1565 GETSHORT(class, p);
1566 p += 4; /* TTL */
1567 GETSHORT(rdlen, p);
1568
1569 if (class == qclass && (type == T_NSEC || type == T_NSEC3))
1570 {
1571 /* No mixed NSECing 'round here, thankyouverymuch */
1572 if (type_found != 0 && type_found != type)
1573 return 0;
1574
1575 type_found = type;
1576
1577 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1578 return 0;
1579
Simon Kelley4fe67442018-01-19 12:26:08 +00001580 if (type == T_NSEC)
1581 {
1582 /* If we're looking for NSECs, find the corresponding SIGs, to
1583 extract the labels value, which we need in case the NSECs
1584 are the result of wildcard expansion.
1585 Note that the NSEC may not have been validated yet
1586 so if there are multiple SIGs, make sure the label value
1587 is the same in all, to avoid be duped by a rogue one.
1588 If there are no SIGs, that's an error */
1589 unsigned char *p1 = auth_start;
1590 int res, j, rdlen1, type1, class1;
1591
1592 if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
1593 return 0;
1594
1595 rrsig_labels[nsecs_found] = NULL;
1596
1597 for (j = ntohs(header->nscount); j != 0; j--)
1598 {
1599 if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
1600 return 0;
1601
1602 GETSHORT(type1, p1);
1603 GETSHORT(class1, p1);
1604 p1 += 4; /* TTL */
1605 GETSHORT(rdlen1, p1);
1606
1607 if (!CHECK_LEN(header, p1, plen, rdlen1))
1608 return 0;
1609
1610 if (res == 1 && class1 == qclass && type1 == T_RRSIG)
1611 {
1612 int type_covered;
1613 unsigned char *psav = p1;
1614
Simon Kelleycd7df612018-01-20 00:10:55 +00001615 if (rdlen1 < 18)
Simon Kelley4fe67442018-01-19 12:26:08 +00001616 return 0; /* bad packet */
1617
1618 GETSHORT(type_covered, p1);
1619
1620 if (type_covered == T_NSEC)
1621 {
1622 p1++; /* algo */
1623
1624 /* labels field must be the same in every SIG we find. */
1625 if (!rrsig_labels[nsecs_found])
1626 rrsig_labels[nsecs_found] = p1;
1627 else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
1628 return 0;
1629 }
1630 p1 = psav;
1631 }
1632
1633 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1634 return 0;
1635 }
1636
1637 /* Must have found at least one sig. */
1638 if (!rrsig_labels[nsecs_found])
1639 return 0;
1640 }
1641
1642 nsecset[nsecs_found++] = pstart;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001643 }
1644
1645 if (!ADD_RDLEN(header, p, plen, rdlen))
1646 return 0;
1647 }
1648
1649 if (type_found == T_NSEC)
Simon Kelley4fe67442018-01-19 12:26:08 +00001650 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 +00001651 else if (type_found == T_NSEC3)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001652 return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001653 else
1654 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001655}
Simon Kelley9a31b682015-12-15 10:20:39 +00001656
1657/* Check signing status of name.
1658 returns:
Simon Kelley3b799c82015-12-17 16:58:04 +00001659 STAT_SECURE zone is signed.
1660 STAT_INSECURE zone proved unsigned.
1661 STAT_NEED_DS require DS record of name returned in keyname.
1662 STAT_NEED_KEY require DNSKEY record of name returned in keyname.
Simon Kelley9a31b682015-12-15 10:20:39 +00001663 name returned unaltered.
1664*/
1665static int zone_status(char *name, int class, char *keyname, time_t now)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001666{
Simon Kelleya63b8b82016-01-12 11:28:58 +00001667 int name_start = strlen(name); /* for when TA is root */
Simon Kelley9a31b682015-12-15 10:20:39 +00001668 struct crec *crecp;
1669 char *p;
Simon Kelleya63b8b82016-01-12 11:28:58 +00001670
1671 /* First, work towards the root, looking for a trust anchor.
1672 This can either be one configured, or one previously cached.
1673 We can assume, if we don't find one first, that there is
1674 a trust anchor at the root. */
1675 for (p = name; p; p = strchr(p, '.'))
1676 {
1677 if (*p == '.')
1678 p++;
1679
1680 if (cache_find_by_name(NULL, p, now, F_DS))
1681 {
1682 name_start = p - name;
1683 break;
1684 }
1685 }
Simon Kelley367341f2016-01-12 15:58:23 +00001686
Simon Kelleya63b8b82016-01-12 11:28:58 +00001687 /* Now work away from the trust anchor */
Simon Kelley9a31b682015-12-15 10:20:39 +00001688 while (1)
1689 {
1690 strcpy(keyname, &name[name_start]);
1691
1692 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
1693 return STAT_NEED_DS;
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001694
Josh Soref730c6742017-02-06 16:14:04 +00001695 /* F_DNSSECOK misused in DS cache records to non-existence of NS record.
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001696 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
1697 but that's because there's no NS record either, ie this isn't the start
1698 of a zone. We only prove that the DNS tree below a node is unsigned when
1699 we prove that we're at a zone cut AND there's no DS record. */
1700 if (crecp->flags & F_NEG)
1701 {
1702 if (crecp->flags & F_DNSSECOK)
1703 return STAT_INSECURE; /* proved no DS here */
1704 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001705 else
Simon Kelley2dbba342015-12-16 13:41:58 +00001706 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001707 /* If all the DS records have digest and/or sig algos we don't support,
1708 then the zone is insecure. Note that if an algo
1709 appears in the DS, then RRSIGs for that algo MUST
1710 exist for each RRset: 4035 para 2.2 So if we find
1711 a DS here with digest and sig we can do, we're entitled
1712 to assume we can validate the zone and if we can't later,
1713 because an RRSIG is missing we return BOGUS.
1714 */
Simon Kelley2dbba342015-12-16 13:41:58 +00001715 do
1716 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001717 if (crecp->uid == (unsigned int)class &&
Simon Kelleyb77efc12017-10-27 23:23:53 +01001718 ds_digest_name(crecp->addr.ds.digest) &&
1719 algo_digest_name(crecp->addr.ds.algo))
Simon Kelleya86fdf42015-12-20 21:19:20 +00001720 break;
Simon Kelley2dbba342015-12-16 13:41:58 +00001721 }
1722 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
Simon Kelley2dbba342015-12-16 13:41:58 +00001723
Simon Kelleya86fdf42015-12-20 21:19:20 +00001724 if (!crecp)
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001725 return STAT_INSECURE;
Simon Kelley2dbba342015-12-16 13:41:58 +00001726 }
1727
Simon Kelley9a31b682015-12-15 10:20:39 +00001728 if (name_start == 0)
1729 break;
1730
1731 for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
1732
1733 if (p != name)
1734 p++;
1735
1736 name_start = p - name;
1737 }
1738
1739 return STAT_SECURE;
1740}
1741
1742/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3)
1743 Return code:
1744 STAT_SECURE if it validates.
1745 STAT_INSECURE at least one RRset not validated, because in unsigned zone.
1746 STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
1747 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
Simon Kelleya6004d72017-10-25 17:48:19 +01001748 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
1749
Simon Kelley373e9172017-12-01 22:40:56 +00001750 daemon->rr_status points to a char array which corressponds to the RRs in the
Simon Kelleya6004d72017-10-25 17:48:19 +01001751 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 +00001752*/
1753int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
Simon Kelley373e9172017-12-01 22:40:56 +00001754 int *class, int check_unsigned, int *neganswer, int *nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001755{
1756 static unsigned char **targets = NULL;
1757 static int target_sz = 0;
1758
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001759 unsigned char *ans_start, *p1, *p2;
Simon Kelleya6004d72017-10-25 17:48:19 +01001760 int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001761 int i, j, rc;
Simon Kelleya6004d72017-10-25 17:48:19 +01001762 int secure = STAT_SECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001763
Simon Kelley373e9172017-12-01 22:40:56 +00001764 /* extend rr_status if necessary */
1765 if (daemon->rr_status_sz < ntohs(header->ancount))
1766 {
1767 char *new = whine_malloc(ntohs(header->ancount) + 64);
1768
1769 if (!new)
1770 return STAT_BOGUS;
1771
1772 free(daemon->rr_status);
1773 daemon->rr_status = new;
1774 daemon->rr_status_sz = ntohs(header->ancount) + 64;
1775 }
1776
1777 memset(daemon->rr_status, 0, ntohs(header->ancount));
Simon Kelleya6004d72017-10-25 17:48:19 +01001778
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001779 if (neganswer)
1780 *neganswer = 0;
1781
Simon Kelley87070192014-03-01 20:48:24 +00001782 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001783 return STAT_BOGUS;
1784
Simon Kelley87070192014-03-01 20:48:24 +00001785 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001786 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001787
Simon Kelley9a31b682015-12-15 10:20:39 +00001788 p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001789
Simon Kelley9a31b682015-12-15 10:20:39 +00001790 /* Find all the targets we're looking for answers to.
1791 The zeroth array element is for the query, subsequent ones
1792 for CNAME targets, unless the query is for a CNAME. */
1793
1794 if (!expand_workspace(&targets, &target_sz, 0))
1795 return STAT_BOGUS;
1796
1797 targets[0] = p1;
1798 targetidx = 1;
1799
Simon Kelley394ff492015-03-29 22:17:14 +01001800 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001801 return STAT_BOGUS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001802
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001803 GETSHORT(qtype, p1);
1804 GETSHORT(qclass, p1);
1805 ans_start = p1;
1806
Simon Kelley9a31b682015-12-15 10:20:39 +00001807 /* Can't validate an RRSIG query */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001808 if (qtype == T_RRSIG)
1809 return STAT_INSECURE;
Simon Kelleye3ec6f02015-06-12 21:39:11 +01001810
Simon Kelley9a31b682015-12-15 10:20:39 +00001811 if (qtype != T_CNAME)
1812 for (j = ntohs(header->ancount); j != 0; j--)
1813 {
1814 if (!(p1 = skip_name(p1, header, plen, 10)))
1815 return STAT_BOGUS; /* bad packet */
1816
1817 GETSHORT(type2, p1);
1818 p1 += 6; /* class, TTL */
1819 GETSHORT(rdlen2, p1);
1820
1821 if (type2 == T_CNAME)
1822 {
1823 if (!expand_workspace(&targets, &target_sz, targetidx))
1824 return STAT_BOGUS;
1825
1826 targets[targetidx++] = p1; /* pointer to target name */
1827 }
1828
1829 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1830 return STAT_BOGUS;
1831 }
1832
Simon Kelley0fc2f312014-01-08 10:26:58 +00001833 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001834 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001835 if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
1836 return STAT_BOGUS;
1837
1838 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001839 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001840
1841 GETSHORT(type1, p1);
1842 GETSHORT(class1, p1);
1843 p1 += 4; /* TTL */
1844 GETSHORT(rdlen1, p1);
1845
1846 /* Don't try and validate RRSIGs! */
Simon Kelleya6004d72017-10-25 17:48:19 +01001847 if (type1 == T_RRSIG)
1848 continue;
1849
1850 /* Check if we've done this RRset already */
1851 for (p2 = ans_start, j = 0; j < i; j++)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001852 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001853 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1854 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001855
Simon Kelleya6004d72017-10-25 17:48:19 +01001856 GETSHORT(type2, p2);
1857 GETSHORT(class2, p2);
1858 p2 += 4; /* TTL */
1859 GETSHORT(rdlen2, p2);
1860
1861 if (type2 == type1 && class2 == class1 && rc == 1)
1862 break; /* Done it before: name, type, class all match. */
1863
1864 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1865 return STAT_BOGUS;
1866 }
1867
1868 if (j != i)
1869 {
1870 /* Done already: copy the validation status */
Simon Kelley373e9172017-12-01 22:40:56 +00001871 if (i < ntohs(header->ancount))
1872 daemon->rr_status[i] = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +01001873 }
1874 else
1875 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001876 /* Not done, validate now */
Simon Kelleya6004d72017-10-25 17:48:19 +01001877 int sigcnt, rrcnt;
1878 char *wildname;
1879
1880 if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
1881 return STAT_BOGUS;
1882
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001883 /* 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 +01001884 if (sigcnt == 0)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001885 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001886 if (check_unsigned)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001887 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001888 rc = zone_status(name, class1, keyname, now);
1889 if (rc == STAT_SECURE)
1890 rc = STAT_BOGUS;
1891 if (class)
1892 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001893 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001894 else
1895 rc = STAT_INSECURE;
Simon Kelley5107ace2014-02-23 10:48:32 +00001896
Simon Kelleya6004d72017-10-25 17:48:19 +01001897 if (rc != STAT_INSECURE)
1898 return rc;
1899 }
1900 else
1901 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001902 /* explore_rrset() gives us key name from sigs in keyname.
1903 Can't overwrite name here. */
1904 strcpy(daemon->workspacename, keyname);
1905 rc = zone_status(daemon->workspacename, class1, keyname, now);
Simon Kelleya6004d72017-10-25 17:48:19 +01001906
1907 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001908 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001909 /* Zone is insecure, don't need to validate RRset */
1910 if (class)
Simon Kelley3b799c82015-12-17 16:58:04 +00001911 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley9a31b682015-12-15 10:20:39 +00001912 return rc;
Simon Kelleya6004d72017-10-25 17:48:19 +01001913 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001914
Simon Kelleya6004d72017-10-25 17:48:19 +01001915 /* Zone is insecure, don't need to validate RRset */
1916 if (rc == STAT_SECURE)
Simon Kelley9a31b682015-12-15 10:20:39 +00001917 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001918 rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
1919 rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
1920
1921 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
1922 {
1923 if (class)
1924 *class = class1; /* Class for DS or DNSKEY */
1925 return rc;
1926 }
1927
Simon Kelley9a31b682015-12-15 10:20:39 +00001928 /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
Simon Kelleya6004d72017-10-25 17:48:19 +01001929
1930 /* Note that RR is validated */
Simon Kelley373e9172017-12-01 22:40:56 +00001931 if (i < ntohs(header->ancount))
1932 daemon->rr_status[i] = 1;
Simon Kelleya6004d72017-10-25 17:48:19 +01001933
Simon Kelley9a31b682015-12-15 10:20:39 +00001934 /* Note if we've validated either the answer to the question
1935 or the target of a CNAME. Any not noted will need NSEC or
1936 to be in unsigned space. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001937 for (j = 0; j <targetidx; j++)
1938 if ((p2 = targets[j]))
1939 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001940 int rc1;
1941 if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001942 return STAT_BOGUS; /* bad packet */
1943
Simon Kelleya6004d72017-10-25 17:48:19 +01001944 if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
Simon Kelley9a31b682015-12-15 10:20:39 +00001945 targets[j] = NULL;
1946 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001947
1948 /* An attacker replay a wildcard answer with a different
1949 answer and overlay a genuine RR. To prove this
1950 hasn't happened, the answer must prove that
1951 the genuine record doesn't exist. Check that here.
1952 Note that we may not yet have validated the NSEC/NSEC3 RRsets.
1953 That's not a problem since if the RRsets later fail
1954 we'll return BOGUS then. */
1955 if (rc == STAT_SECURE_WILDCARD &&
1956 !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001957 return STAT_BOGUS;
Simon Kelleya6004d72017-10-25 17:48:19 +01001958
1959 rc = STAT_SECURE;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001960 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001961 }
1962 }
1963
Simon Kelleya6004d72017-10-25 17:48:19 +01001964 if (rc == STAT_INSECURE)
1965 secure = STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001966 }
1967
Simon Kelley9a31b682015-12-15 10:20:39 +00001968 /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
Simon Kelley4e72fec2018-04-11 22:49:31 +01001969 if (check_unsigned)
1970 for (j = 0; j <targetidx; j++)
1971 if ((p2 = targets[j]))
1972 {
1973 if (neganswer)
1974 *neganswer = 1;
1975
1976 if (!extract_name(header, plen, &p2, name, 1, 10))
1977 return STAT_BOGUS; /* bad packet */
1978
1979 /* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
1980
1981 /* For anything other than a DS record, this situation is OK if either
1982 the answer is in an unsigned zone, or there's a NSEC records. */
1983 if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
1984 {
1985 /* Empty DS without NSECS */
1986 if (qtype == T_DS)
1987 return STAT_BOGUS;
1988
1989 if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
1990 {
1991 if (class)
1992 *class = qclass; /* Class for NEED_DS or NEED_KEY */
1993 return rc;
1994 }
1995
1996 return STAT_BOGUS; /* signed zone, no NSECs */
1997 }
1998 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001999
Simon Kelleya6004d72017-10-25 17:48:19 +01002000 return secure;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002001}
2002
2003
Giovanni Bajo3471f182012-04-25 17:49:16 +02002004/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002005int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02002006{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002007 if (alg == 1)
2008 {
2009 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
2010 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002011 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002012 }
2013 else
2014 {
Simon Kelley1633e302014-02-10 16:42:46 +00002015 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002016 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002017
Simon Kelley0fc2f312014-01-08 10:26:58 +00002018 for (i = 0; i < keylen; ++i)
2019 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002020
Simon Kelley0fc2f312014-01-08 10:26:58 +00002021 ac += (ac >> 16) & 0xffff;
2022 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002023 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002024}
2025
Simon Kelley33702ab2015-12-28 23:17:15 +00002026size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
Simon Kelleya77cec82015-05-08 16:25:38 +01002027 int type, union mysockaddr *addr, int edns_pktsz)
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002028{
2029 unsigned char *p;
Simon Kelley610e7822014-02-06 14:45:17 +00002030 char *types = querystr("dnssec-query", type);
Simon Kelleya77cec82015-05-08 16:25:38 +01002031 size_t ret;
Giovanni Bajo0304d282012-05-02 03:29:52 +02002032
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002033 if (addr->sa.sa_family == AF_INET)
Simon Kelley25cf5e32015-01-09 15:53:03 +00002034 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002035#ifdef HAVE_IPV6
2036 else
Simon Kelley25cf5e32015-01-09 15:53:03 +00002037 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002038#endif
2039
2040 header->qdcount = htons(1);
2041 header->ancount = htons(0);
2042 header->nscount = htons(0);
2043 header->arcount = htons(0);
2044
2045 header->hb3 = HB3_RD;
2046 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002047 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2048 this allows it to select auth servers when one is returning bad data. */
2049 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002050
2051 /* ID filled in later */
2052
2053 p = (unsigned char *)(header+1);
2054
Simon Kelley0549c732017-09-25 18:17:11 +01002055 p = do_rfc1035_name(p, name, NULL);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002056 *p++ = 0;
2057 PUTSHORT(type, p);
2058 PUTSHORT(class, p);
2059
Simon Kelleya77cec82015-05-08 16:25:38 +01002060 ret = add_do_bit(header, p - (unsigned char *)header, end);
2061
Simon Kelley5bb88f02015-12-21 16:23:47 +00002062 if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
Simon Kelleya77cec82015-05-08 16:25:38 +01002063 PUTSHORT(edns_pktsz, p);
2064
2065 return ret;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002066}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002067
2068unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2069{
2070 int q;
2071 unsigned int len;
2072 unsigned char *p = (unsigned char *)(header+1);
2073 const struct nettle_hash *hash;
2074 void *ctx;
2075 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002076
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002077 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2078 return NULL;
2079
2080 for (q = ntohs(header->qdcount); q != 0; q--)
2081 {
Simon Kelley394ff492015-03-29 22:17:14 +01002082 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002083 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002084
2085 len = to_wire(name);
2086 hash->update(ctx, len, (unsigned char *)name);
2087 /* CRC the class and type as well */
2088 hash->update(ctx, 4, p);
2089
2090 p += 4;
2091 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002092 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002093 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002094
2095 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002096 return digest;
2097}
2098
Simon Kelley0fc2f312014-01-08 10:26:58 +00002099#endif /* HAVE_DNSSEC */