blob: dcb3f1564f8e8170538b993c56a31da40ca5477f [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 Kelley7f008432018-04-15 20:01:49 +0100875 rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
Simon Kelley97e618a2015-01-07 21:55:43 +0000876
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000877 if (rc == STAT_INSECURE)
Simon Kelley7f008432018-04-15 20:01:49 +0100878 {
Simon Kelleyf84e6742018-05-04 16:29:57 +0100879 my_syslog(LOG_WARNING, _("Insecure DS reply received, do upstream DNS servers support DNSSEC?"));
Simon Kelley7f008432018-04-15 20:01:49 +0100880 rc = STAT_BOGUS;
881 }
882
Simon Kelleyb8eac192014-02-27 14:30:03 +0000883 p = (unsigned char *)(header+1);
Simon Kelley394ff492015-03-29 22:17:14 +0100884 extract_name(header, plen, &p, name, 1, 4);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000885 p += 4; /* qtype, qclass */
886
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000887 /* If the key needed to validate the DS is on the same domain as the DS, we'll
888 loop getting nowhere. Stop that now. This can happen of the DS answer comes
889 from the DS's zone, and not the parent zone. */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000890 if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
Simon Kelleyb8eac192014-02-27 14:30:03 +0000891 {
Simon Kelley25cf5e32015-01-09 15:53:03 +0000892 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
Simon Kelley97e618a2015-01-07 21:55:43 +0000893 return STAT_BOGUS;
894 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000895
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000896 if (rc != STAT_SECURE)
897 return rc;
898
899 if (!neganswer)
Simon Kelley97e618a2015-01-07 21:55:43 +0000900 {
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000901 cache_start_insert();
902
903 for (i = 0; i < ntohs(header->ancount); i++)
904 {
905 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
906 return STAT_BOGUS; /* bad packet */
907
908 GETSHORT(atype, p);
909 GETSHORT(aclass, p);
910 GETLONG(ttl, p);
911 GETSHORT(rdlen, p);
912
913 if (!CHECK_LEN(header, p, plen, rdlen))
914 return STAT_BOGUS; /* bad packet */
915
916 if (aclass == class && atype == T_DS && rc == 1)
917 {
918 int algo, digest, keytag;
919 unsigned char *psave = p;
920 struct blockdata *key;
921 struct crec *crecp;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000922
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000923 if (rdlen < 4)
924 return STAT_BOGUS; /* bad packet */
925
926 GETSHORT(keytag, p);
927 algo = *p++;
928 digest = *p++;
929
930 /* Cache needs to known class for DNSSEC stuff */
931 a.addr.dnssec.class = class;
932
933 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
934 {
935 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
936 {
937 blockdata_free(key);
938 return STAT_BOGUS;
939 }
940 else
941 {
Simon Kelley15379ea2015-12-21 18:31:55 +0000942 a.addr.log.keytag = keytag;
943 a.addr.log.algo = algo;
944 a.addr.log.digest = digest;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100945 if (ds_digest_name(digest) && algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000946 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000947 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000948 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 +0000949
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000950 crecp->addr.ds.digest = digest;
951 crecp->addr.ds.keydata = key;
952 crecp->addr.ds.algo = algo;
953 crecp->addr.ds.keytag = keytag;
954 crecp->addr.ds.keylen = rdlen - 4;
955 }
956 }
957
958 p = psave;
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000959 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000960 if (!ADD_RDLEN(header, p, plen, rdlen))
961 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000962 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000963
964 cache_end_insert();
965
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000966 }
967 else
968 {
969 int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
970 unsigned long minttl = ULONG_MAX;
971
972 if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
973 return STAT_BOGUS;
974
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000975 if (RCODE(header) == NXDOMAIN)
976 flags |= F_NXDOMAIN;
977
Simon Kelley97e618a2015-01-07 21:55:43 +0000978 /* We only cache validated DS records, DNSSECOK flag hijacked
979 to store presence/absence of NS. */
980 if (nons)
981 flags &= ~F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000982
983 for (i = ntohs(header->nscount); i != 0; i--)
984 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000985 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +0000986 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000987
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000988 GETSHORT(atype, p);
989 GETSHORT(aclass, p);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000990 GETLONG(ttl, p);
991 GETSHORT(rdlen, p);
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000992
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000993 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000994 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000995
996 if (aclass != class || atype != T_SOA)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000997 {
998 p += rdlen;
999 continue;
1000 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001001
Simon Kelleyb8eac192014-02-27 14:30:03 +00001002 if (ttl < minttl)
1003 minttl = ttl;
1004
1005 /* MNAME */
1006 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001007 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001008 /* RNAME */
1009 if (!(p = skip_name(p, header, plen, 20)))
Simon Kelley87070192014-03-01 20:48:24 +00001010 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001011 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
1012
1013 GETLONG(ttl, p); /* minTTL */
1014 if (ttl < minttl)
1015 minttl = ttl;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001016
1017 break;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001018 }
1019
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001020 if (i != 0)
1021 {
1022 cache_start_insert();
1023
1024 a.addr.dnssec.class = class;
Simon Kelley93be5b12015-12-15 12:04:40 +00001025 if (!cache_insert(name, &a, now, ttl, flags))
1026 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001027
Simon Kelley97e618a2015-01-07 21:55:43 +00001028 cache_end_insert();
1029
Simon Kelley9a31b682015-12-15 10:20:39 +00001030 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001031 }
Simon Kelleyb8eac192014-02-27 14:30:03 +00001032 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001033
Simon Kelley9a31b682015-12-15 10:20:39 +00001034 return STAT_OK;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001035}
1036
Simon Kelley9a31b682015-12-15 10:20:39 +00001037
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001038/* 4034 6.1 */
1039static int hostname_cmp(const char *a, const char *b)
1040{
Simon Kelleydbf72122014-01-21 14:28:02 +00001041 char *sa, *ea, *ca, *sb, *eb, *cb;
1042 unsigned char ac, bc;
1043
1044 sa = ea = (char *)a + strlen(a);
1045 sb = eb = (char *)b + strlen(b);
1046
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001047 while (1)
1048 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001049 while (sa != a && *(sa-1) != '.')
1050 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001051
Simon Kelleydbf72122014-01-21 14:28:02 +00001052 while (sb != b && *(sb-1) != '.')
1053 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001054
Simon Kelleydbf72122014-01-21 14:28:02 +00001055 ca = sa;
1056 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001057
Simon Kelleydbf72122014-01-21 14:28:02 +00001058 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001059 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001060 if (ca == ea)
1061 {
1062 if (cb == eb)
1063 break;
1064
1065 return -1;
1066 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001067
Simon Kelleydbf72122014-01-21 14:28:02 +00001068 if (cb == eb)
1069 return 1;
1070
1071 ac = (unsigned char) *ca++;
1072 bc = (unsigned char) *cb++;
1073
1074 if (ac >= 'A' && ac <= 'Z')
1075 ac += 'a' - 'A';
1076 if (bc >= 'A' && bc <= 'Z')
1077 bc += 'a' - 'A';
1078
Simon Kelley979cdf92014-01-21 16:26:41 +00001079 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001080 return -1;
1081 else if (ac != bc)
1082 return 1;
1083 }
1084
1085
1086 if (sa == a)
1087 {
1088 if (sb == b)
1089 return 0;
1090
1091 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001092 }
1093
Simon Kelleydbf72122014-01-21 14:28:02 +00001094 if (sb == b)
1095 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001096
Simon Kelley3e86d312015-12-20 20:50:05 +00001097 ea = --sa;
1098 eb = --sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001099 }
1100}
1101
Simon Kelley4fe67442018-01-19 12:26:08 +00001102static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
1103 char *workspace1_in, char *workspace2, char *name, int type, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001104{
1105 int i, rc, rdlen;
1106 unsigned char *p, *psave;
1107 int offset = (type & 0xff) >> 3;
1108 int mask = 0x80 >> (type & 0x07);
Simon Kelley97e618a2015-01-07 21:55:43 +00001109
1110 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001111 *nons = 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001112
1113 /* Find NSEC record that proves name doesn't exist */
1114 for (i = 0; i < nsec_count; i++)
1115 {
Simon Kelley4fe67442018-01-19 12:26:08 +00001116 char *workspace1 = workspace1_in;
1117 int sig_labels, name_labels;
1118
Simon Kelley5107ace2014-02-23 10:48:32 +00001119 p = nsecs[i];
Simon Kelley394ff492015-03-29 22:17:14 +01001120 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001121 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001122 p += 8; /* class, type, TTL */
1123 GETSHORT(rdlen, p);
1124 psave = p;
Simon Kelley394ff492015-03-29 22:17:14 +01001125 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001126 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001127
1128 /* If NSEC comes from wildcard expansion, use original wildcard
1129 as name for computation. */
1130 sig_labels = *labels[i];
1131 name_labels = count_labels(workspace1);
1132
1133 if (sig_labels < name_labels)
1134 {
1135 int k;
1136 for (k = name_labels - sig_labels; k != 0; k--)
1137 {
1138 while (*workspace1 != '.' && *workspace1 != 0)
1139 workspace1++;
1140 if (k != 1 && *workspace1 == '.')
1141 workspace1++;
1142 }
1143
1144 workspace1--;
1145 *workspace1 = '*';
1146 }
1147
Simon Kelley5107ace2014-02-23 10:48:32 +00001148 rc = hostname_cmp(workspace1, name);
1149
1150 if (rc == 0)
1151 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001152 /* 4035 para 5.4. Last sentence */
1153 if (type == T_NSEC || type == T_RRSIG)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001154 return 1;
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001155
Simon Kelley5107ace2014-02-23 10:48:32 +00001156 /* NSEC with the same name as the RR we're testing, check
1157 that the type in question doesn't appear in the type map */
1158 rdlen -= p - psave;
1159 /* rdlen is now length of type map, and p points to it */
1160
Simon Kelley97e618a2015-01-07 21:55:43 +00001161 /* If we can prove that there's no NS record, return that information. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001162 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
1163 *nons = 0;
Simon Kelley97e618a2015-01-07 21:55:43 +00001164
Simon Kelley9a31b682015-12-15 10:20:39 +00001165 if (rdlen >= 2 && p[0] == 0)
1166 {
1167 /* A CNAME answer would also be valid, so if there's a CNAME is should
1168 have been returned. */
1169 if ((p[2] & (0x80 >> T_CNAME)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001170 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001171
1172 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001173 DS from the wrong side of the delegation. For the root DS,
1174 this is expected. */
1175 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001176 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001177 }
1178
Simon Kelley5107ace2014-02-23 10:48:32 +00001179 while (rdlen >= 2)
1180 {
1181 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001182 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001183
1184 if (p[0] == type >> 8)
1185 {
1186 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001187 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001188 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001189
Josh Soref730c6742017-02-06 16:14:04 +00001190 break; /* finished checking */
Simon Kelley5107ace2014-02-23 10:48:32 +00001191 }
1192
1193 rdlen -= p[1];
1194 p += p[1];
1195 }
1196
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001197 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001198 }
1199 else if (rc == -1)
1200 {
1201 /* Normal case, name falls between NSEC name and next domain name,
1202 wrap around case, name falls between NSEC name (rc == -1) and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001203 if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001204 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001205 }
1206 else
1207 {
1208 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001209 if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001210 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001211 }
1212 }
1213
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001214 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001215}
1216
1217/* return digest length, or zero on error */
1218static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1219 unsigned char *salt, int salt_len, int iterations)
1220{
1221 void *ctx;
1222 unsigned char *digest;
1223 int i;
1224
1225 if (!hash_init(hash, &ctx, &digest))
1226 return 0;
1227
1228 hash->update(ctx, to_wire(in), (unsigned char *)in);
1229 hash->update(ctx, salt_len, salt);
1230 hash->digest(ctx, hash->digest_size, digest);
1231
1232 for(i = 0; i < iterations; i++)
1233 {
1234 hash->update(ctx, hash->digest_size, digest);
1235 hash->update(ctx, salt_len, salt);
1236 hash->digest(ctx, hash->digest_size, digest);
1237 }
1238
1239 from_wire(in);
1240
1241 *out = digest;
1242 return hash->digest_size;
1243}
1244
1245/* Decode base32 to first "." or end of string */
1246static int base32_decode(char *in, unsigned char *out)
1247{
Simon Kelleya857daa2014-02-24 21:01:09 +00001248 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001249 unsigned char *p = out;
1250
Simon Kelleya857daa2014-02-24 21:01:09 +00001251 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001252 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001253 if (c >= '0' && c <= '9')
1254 c -= '0';
1255 else if (c >= 'a' && c <= 'v')
1256 c -= 'a', c += 10;
1257 else if (c >= 'A' && c <= 'V')
1258 c -= 'A', c += 10;
1259 else
1260 return 0;
1261
1262 for (mask = 0x10, i = 0; i < 5; i++)
1263 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001264 if (c & mask)
1265 oc |= 1;
1266 mask = mask >> 1;
1267 if (((++on) & 7) == 0)
1268 *p++ = oc;
1269 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001270 }
1271 }
1272
1273 if ((on & 7) != 0)
1274 return 0;
1275
1276 return p - out;
1277}
1278
Simon Kelleyfbc52052014-12-23 15:46:08 +00001279static 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 +00001280 char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001281{
Simon Kelley9a31b682015-12-15 10:20:39 +00001282 int i, hash_len, salt_len, base32_len, rdlen, flags;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001283 unsigned char *p, *psave;
1284
1285 for (i = 0; i < nsec_count; i++)
1286 if ((p = nsecs[i]))
1287 {
Simon Kelley394ff492015-03-29 22:17:14 +01001288 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleyfbc52052014-12-23 15:46:08 +00001289 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
1290 return 0;
1291
1292 p += 8; /* class, type, TTL */
1293 GETSHORT(rdlen, p);
1294 psave = p;
Simon Kelley9a31b682015-12-15 10:20:39 +00001295 p++; /* algo */
1296 flags = *p++; /* flags */
1297 p += 2; /* iterations */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001298 salt_len = *p++; /* salt_len */
1299 p += salt_len; /* salt */
1300 hash_len = *p++; /* p now points to next hashed name */
1301
1302 if (!CHECK_LEN(header, p, plen, hash_len))
1303 return 0;
1304
1305 if (digest_len == base32_len && hash_len == base32_len)
1306 {
1307 int rc = memcmp(workspace2, digest, digest_len);
1308
1309 if (rc == 0)
1310 {
1311 /* We found an NSEC3 whose hashed name exactly matches the query, so
1312 we just need to check the type map. p points to the RR data for the record. */
1313
1314 int offset = (type & 0xff) >> 3;
1315 int mask = 0x80 >> (type & 0x07);
1316
1317 p += hash_len; /* skip next-domain hash */
1318 rdlen -= p - psave;
1319
1320 if (!CHECK_LEN(header, p, plen, rdlen))
1321 return 0;
1322
Simon Kelley9a31b682015-12-15 10:20:39 +00001323 if (rdlen >= 2 && p[0] == 0)
1324 {
Simon Kelleyec0628c2015-12-31 20:55:39 +00001325 /* If we can prove that there's no NS record, return that information. */
1326 if (nons && (p[2] & (0x80 >> T_NS)) != 0)
1327 *nons = 0;
1328
Simon Kelley9a31b682015-12-15 10:20:39 +00001329 /* A CNAME answer would also be valid, so if there's a CNAME is should
1330 have been returned. */
1331 if ((p[2] & (0x80 >> T_CNAME)) != 0)
1332 return 0;
1333
1334 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001335 DS from the wrong side of the delegation. For the root DS,
1336 this is expected. */
1337 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001338 return 0;
1339 }
1340
Simon Kelleyfbc52052014-12-23 15:46:08 +00001341 while (rdlen >= 2)
1342 {
1343 if (p[0] == type >> 8)
1344 {
1345 /* Does the NSEC3 say our type exists? */
1346 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001347 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001348
Josh Soref730c6742017-02-06 16:14:04 +00001349 break; /* finished checking */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001350 }
1351
1352 rdlen -= p[1];
1353 p += p[1];
1354 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001355
Simon Kelleyfbc52052014-12-23 15:46:08 +00001356 return 1;
1357 }
Simon Kelley4d25cf82015-06-06 23:13:57 +01001358 else if (rc < 0)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001359 {
1360 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1361 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001362 if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001363 {
1364 if ((flags & 0x01) && nons) /* opt out */
1365 *nons = 0;
1366
1367 return 1;
1368 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001369 }
1370 else
1371 {
1372 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001373 if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001374 {
1375 if ((flags & 0x01) && nons) /* opt out */
1376 *nons = 0;
1377
1378 return 1;
1379 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001380 }
1381 }
1382 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001383
Simon Kelleyfbc52052014-12-23 15:46:08 +00001384 return 0;
1385}
1386
Simon Kelley24187532014-02-24 21:46:44 +00001387static 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 +00001388 char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001389{
Simon Kelleya857daa2014-02-24 21:01:09 +00001390 unsigned char *salt, *p, *digest;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001391 int digest_len, i, iterations, salt_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001392 struct nettle_hash const *hash;
1393 char *closest_encloser, *next_closest, *wildcard;
Simon Kelley97e618a2015-01-07 21:55:43 +00001394
1395 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001396 *nons = 1;
Simon Kelley97e618a2015-01-07 21:55:43 +00001397
Simon Kelley5107ace2014-02-23 10:48:32 +00001398 /* Look though the NSEC3 records to find the first one with
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001399 an algorithm we support.
Simon Kelley5107ace2014-02-23 10:48:32 +00001400
1401 Take the algo, iterations, and salt of that record
1402 as the ones we're going to use, and prune any
1403 that don't match. */
1404
1405 for (i = 0; i < nsec_count; i++)
1406 {
1407 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001408 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001409
1410 p += 10; /* type, class, TTL, rdlen */
1411 algo = *p++;
1412
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001413 if ((hash = hash_find(nsec3_digest_name(algo))))
Simon Kelley5107ace2014-02-23 10:48:32 +00001414 break; /* known algo */
1415 }
1416
1417 /* No usable NSEC3s */
1418 if (i == nsec_count)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001419 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001420
1421 p++; /* flags */
Simon Kelley40205a02016-03-14 21:24:00 +00001422
Simon Kelley5107ace2014-02-23 10:48:32 +00001423 GETSHORT (iterations, p);
Simon Kelley40205a02016-03-14 21:24:00 +00001424 /* Upper-bound iterations, to avoid DoS.
1425 Strictly, there are lower bounds for small keys, but
1426 since we don't have key size info here, at least limit
1427 to the largest bound, for 4096-bit keys. RFC 5155 10.3 */
1428 if (iterations > 2500)
1429 return 0;
1430
Simon Kelley5107ace2014-02-23 10:48:32 +00001431 salt_len = *p++;
1432 salt = p;
1433 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001434 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001435
1436 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1437 for (i = 0; i < nsec_count; i++)
1438 {
1439 unsigned char *nsec3p = nsecs[i];
Simon Kelleyce5732e2015-12-20 21:39:19 +00001440 int this_iter, flags;
Simon Kelley5107ace2014-02-23 10:48:32 +00001441
1442 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1443
1444 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001445 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001446
1447 p += 10; /* type, class, TTL, rdlen */
1448
1449 if (*p++ != algo)
1450 continue;
1451
Simon Kelleyce5732e2015-12-20 21:39:19 +00001452 flags = *p++; /* flags */
Simon Kelley5107ace2014-02-23 10:48:32 +00001453
Simon Kelleyce5732e2015-12-20 21:39:19 +00001454 /* 5155 8.2 */
1455 if (flags != 0 && flags != 1)
1456 continue;
1457
Simon Kelleya857daa2014-02-24 21:01:09 +00001458 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001459 if (this_iter != iterations)
1460 continue;
1461
1462 if (salt_len != *p++)
1463 continue;
1464
1465 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001466 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001467
1468 if (memcmp(p, salt, salt_len) != 0)
1469 continue;
1470
1471 /* All match, put the pointer back */
1472 nsecs[i] = nsec3p;
1473 }
1474
Simon Kelleyfbc52052014-12-23 15:46:08 +00001475 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001476 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001477
Simon Kelleya969ba62018-01-20 23:08:38 +00001478 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 +00001479 return 1;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001480
1481 /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
1482 or an answer inferred from a wildcard record. */
Simon Kelley5107ace2014-02-23 10:48:32 +00001483 closest_encloser = name;
1484 next_closest = NULL;
1485
1486 do
1487 {
1488 if (*closest_encloser == '.')
1489 closest_encloser++;
1490
Simon Kelleyfbc52052014-12-23 15:46:08 +00001491 if (wildname && hostname_isequal(closest_encloser, wildname))
1492 break;
1493
Simon Kelleya857daa2014-02-24 21:01:09 +00001494 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001495 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001496
1497 for (i = 0; i < nsec_count; i++)
1498 if ((p = nsecs[i]))
1499 {
Simon Kelley394ff492015-03-29 22:17:14 +01001500 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001501 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001502 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001503
Simon Kelleya857daa2014-02-24 21:01:09 +00001504 if (digest_len == base32_len &&
1505 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001506 break; /* Gotit */
1507 }
1508
1509 if (i != nsec_count)
1510 break;
1511
1512 next_closest = closest_encloser;
1513 }
1514 while ((closest_encloser = strchr(closest_encloser, '.')));
1515
Simon Kelleya7b27e82016-03-16 19:11:52 +00001516 if (!closest_encloser || !next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001517 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001518
Simon Kelley24187532014-02-24 21:46:44 +00001519 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001520 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001521 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001522
Simon Kelleya969ba62018-01-20 23:08:38 +00001523 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001524 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001525
1526 /* Finally, check that there's no seat of wildcard synthesis */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001527 if (!wildname)
1528 {
1529 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001530 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001531
1532 wildcard--;
1533 *wildcard = '*';
1534
1535 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001536 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001537
Simon Kelleya969ba62018-01-20 23:08:38 +00001538 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001539 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001540 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001541
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001542 return 1;
1543}
1544
1545static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
1546{
Simon Kelley4fe67442018-01-19 12:26:08 +00001547 static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
1548 static int nsecset_sz = 0, rrsig_labels_sz = 0;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001549
1550 int type_found = 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001551 unsigned char *auth_start, *p = skip_questions(header, plen);
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001552 int type, class, rdlen, i, nsecs_found;
1553
1554 /* Move to NS section */
1555 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1556 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001557
1558 auth_start = p;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001559
1560 for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
1561 {
1562 unsigned char *pstart = p;
1563
Simon Kelley4fe67442018-01-19 12:26:08 +00001564 if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001565 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001566
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001567 GETSHORT(type, p);
1568 GETSHORT(class, p);
1569 p += 4; /* TTL */
1570 GETSHORT(rdlen, p);
1571
1572 if (class == qclass && (type == T_NSEC || type == T_NSEC3))
1573 {
1574 /* No mixed NSECing 'round here, thankyouverymuch */
1575 if (type_found != 0 && type_found != type)
1576 return 0;
1577
1578 type_found = type;
1579
1580 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1581 return 0;
1582
Simon Kelley4fe67442018-01-19 12:26:08 +00001583 if (type == T_NSEC)
1584 {
1585 /* If we're looking for NSECs, find the corresponding SIGs, to
1586 extract the labels value, which we need in case the NSECs
1587 are the result of wildcard expansion.
1588 Note that the NSEC may not have been validated yet
1589 so if there are multiple SIGs, make sure the label value
1590 is the same in all, to avoid be duped by a rogue one.
1591 If there are no SIGs, that's an error */
1592 unsigned char *p1 = auth_start;
1593 int res, j, rdlen1, type1, class1;
1594
1595 if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
1596 return 0;
1597
1598 rrsig_labels[nsecs_found] = NULL;
1599
1600 for (j = ntohs(header->nscount); j != 0; j--)
1601 {
1602 if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
1603 return 0;
1604
1605 GETSHORT(type1, p1);
1606 GETSHORT(class1, p1);
1607 p1 += 4; /* TTL */
1608 GETSHORT(rdlen1, p1);
1609
1610 if (!CHECK_LEN(header, p1, plen, rdlen1))
1611 return 0;
1612
1613 if (res == 1 && class1 == qclass && type1 == T_RRSIG)
1614 {
1615 int type_covered;
1616 unsigned char *psav = p1;
1617
Simon Kelleycd7df612018-01-20 00:10:55 +00001618 if (rdlen1 < 18)
Simon Kelley4fe67442018-01-19 12:26:08 +00001619 return 0; /* bad packet */
1620
1621 GETSHORT(type_covered, p1);
1622
1623 if (type_covered == T_NSEC)
1624 {
1625 p1++; /* algo */
1626
1627 /* labels field must be the same in every SIG we find. */
1628 if (!rrsig_labels[nsecs_found])
1629 rrsig_labels[nsecs_found] = p1;
1630 else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
1631 return 0;
1632 }
1633 p1 = psav;
1634 }
1635
1636 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1637 return 0;
1638 }
1639
1640 /* Must have found at least one sig. */
1641 if (!rrsig_labels[nsecs_found])
1642 return 0;
1643 }
1644
1645 nsecset[nsecs_found++] = pstart;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001646 }
1647
1648 if (!ADD_RDLEN(header, p, plen, rdlen))
1649 return 0;
1650 }
1651
1652 if (type_found == T_NSEC)
Simon Kelley4fe67442018-01-19 12:26:08 +00001653 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 +00001654 else if (type_found == T_NSEC3)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001655 return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001656 else
1657 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001658}
Simon Kelley9a31b682015-12-15 10:20:39 +00001659
1660/* Check signing status of name.
1661 returns:
Simon Kelley3b799c82015-12-17 16:58:04 +00001662 STAT_SECURE zone is signed.
1663 STAT_INSECURE zone proved unsigned.
1664 STAT_NEED_DS require DS record of name returned in keyname.
1665 STAT_NEED_KEY require DNSKEY record of name returned in keyname.
Simon Kelley9a31b682015-12-15 10:20:39 +00001666 name returned unaltered.
1667*/
1668static int zone_status(char *name, int class, char *keyname, time_t now)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001669{
Simon Kelleya63b8b82016-01-12 11:28:58 +00001670 int name_start = strlen(name); /* for when TA is root */
Simon Kelley9a31b682015-12-15 10:20:39 +00001671 struct crec *crecp;
1672 char *p;
Simon Kelleya63b8b82016-01-12 11:28:58 +00001673
1674 /* First, work towards the root, looking for a trust anchor.
1675 This can either be one configured, or one previously cached.
1676 We can assume, if we don't find one first, that there is
1677 a trust anchor at the root. */
1678 for (p = name; p; p = strchr(p, '.'))
1679 {
1680 if (*p == '.')
1681 p++;
1682
1683 if (cache_find_by_name(NULL, p, now, F_DS))
1684 {
1685 name_start = p - name;
1686 break;
1687 }
1688 }
Simon Kelley367341f2016-01-12 15:58:23 +00001689
Simon Kelleya63b8b82016-01-12 11:28:58 +00001690 /* Now work away from the trust anchor */
Simon Kelley9a31b682015-12-15 10:20:39 +00001691 while (1)
1692 {
1693 strcpy(keyname, &name[name_start]);
1694
1695 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
1696 return STAT_NEED_DS;
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001697
Josh Soref730c6742017-02-06 16:14:04 +00001698 /* F_DNSSECOK misused in DS cache records to non-existence of NS record.
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001699 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
1700 but that's because there's no NS record either, ie this isn't the start
1701 of a zone. We only prove that the DNS tree below a node is unsigned when
1702 we prove that we're at a zone cut AND there's no DS record. */
1703 if (crecp->flags & F_NEG)
1704 {
1705 if (crecp->flags & F_DNSSECOK)
1706 return STAT_INSECURE; /* proved no DS here */
1707 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001708 else
Simon Kelley2dbba342015-12-16 13:41:58 +00001709 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001710 /* If all the DS records have digest and/or sig algos we don't support,
1711 then the zone is insecure. Note that if an algo
1712 appears in the DS, then RRSIGs for that algo MUST
1713 exist for each RRset: 4035 para 2.2 So if we find
1714 a DS here with digest and sig we can do, we're entitled
1715 to assume we can validate the zone and if we can't later,
1716 because an RRSIG is missing we return BOGUS.
1717 */
Simon Kelley2dbba342015-12-16 13:41:58 +00001718 do
1719 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001720 if (crecp->uid == (unsigned int)class &&
Simon Kelleyb77efc12017-10-27 23:23:53 +01001721 ds_digest_name(crecp->addr.ds.digest) &&
1722 algo_digest_name(crecp->addr.ds.algo))
Simon Kelleya86fdf42015-12-20 21:19:20 +00001723 break;
Simon Kelley2dbba342015-12-16 13:41:58 +00001724 }
1725 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
Simon Kelley2dbba342015-12-16 13:41:58 +00001726
Simon Kelleya86fdf42015-12-20 21:19:20 +00001727 if (!crecp)
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001728 return STAT_INSECURE;
Simon Kelley2dbba342015-12-16 13:41:58 +00001729 }
1730
Simon Kelley9a31b682015-12-15 10:20:39 +00001731 if (name_start == 0)
1732 break;
1733
1734 for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
1735
1736 if (p != name)
1737 p++;
1738
1739 name_start = p - name;
1740 }
1741
1742 return STAT_SECURE;
1743}
1744
1745/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3)
1746 Return code:
1747 STAT_SECURE if it validates.
1748 STAT_INSECURE at least one RRset not validated, because in unsigned zone.
1749 STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
1750 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
Simon Kelleya6004d72017-10-25 17:48:19 +01001751 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
1752
Simon Kelley373e9172017-12-01 22:40:56 +00001753 daemon->rr_status points to a char array which corressponds to the RRs in the
Simon Kelleya6004d72017-10-25 17:48:19 +01001754 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 +00001755*/
1756int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
Simon Kelley373e9172017-12-01 22:40:56 +00001757 int *class, int check_unsigned, int *neganswer, int *nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001758{
1759 static unsigned char **targets = NULL;
1760 static int target_sz = 0;
1761
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001762 unsigned char *ans_start, *p1, *p2;
Simon Kelleya6004d72017-10-25 17:48:19 +01001763 int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
Simon Kelley91421cb2018-10-18 19:21:55 +01001764 int i, j, rc = STAT_INSECURE;
Simon Kelleya6004d72017-10-25 17:48:19 +01001765 int secure = STAT_SECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001766
Simon Kelley373e9172017-12-01 22:40:56 +00001767 /* extend rr_status if necessary */
1768 if (daemon->rr_status_sz < ntohs(header->ancount))
1769 {
1770 char *new = whine_malloc(ntohs(header->ancount) + 64);
1771
1772 if (!new)
1773 return STAT_BOGUS;
1774
1775 free(daemon->rr_status);
1776 daemon->rr_status = new;
1777 daemon->rr_status_sz = ntohs(header->ancount) + 64;
1778 }
1779
1780 memset(daemon->rr_status, 0, ntohs(header->ancount));
Simon Kelleya6004d72017-10-25 17:48:19 +01001781
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001782 if (neganswer)
1783 *neganswer = 0;
1784
Simon Kelley87070192014-03-01 20:48:24 +00001785 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001786 return STAT_BOGUS;
1787
Simon Kelley87070192014-03-01 20:48:24 +00001788 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001789 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001790
Simon Kelley9a31b682015-12-15 10:20:39 +00001791 p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001792
Simon Kelley9a31b682015-12-15 10:20:39 +00001793 /* Find all the targets we're looking for answers to.
1794 The zeroth array element is for the query, subsequent ones
1795 for CNAME targets, unless the query is for a CNAME. */
1796
1797 if (!expand_workspace(&targets, &target_sz, 0))
1798 return STAT_BOGUS;
1799
1800 targets[0] = p1;
1801 targetidx = 1;
1802
Simon Kelley394ff492015-03-29 22:17:14 +01001803 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001804 return STAT_BOGUS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001805
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001806 GETSHORT(qtype, p1);
1807 GETSHORT(qclass, p1);
1808 ans_start = p1;
1809
Simon Kelley9a31b682015-12-15 10:20:39 +00001810 /* Can't validate an RRSIG query */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001811 if (qtype == T_RRSIG)
1812 return STAT_INSECURE;
Simon Kelleye3ec6f02015-06-12 21:39:11 +01001813
Simon Kelley9a31b682015-12-15 10:20:39 +00001814 if (qtype != T_CNAME)
1815 for (j = ntohs(header->ancount); j != 0; j--)
1816 {
1817 if (!(p1 = skip_name(p1, header, plen, 10)))
1818 return STAT_BOGUS; /* bad packet */
1819
1820 GETSHORT(type2, p1);
1821 p1 += 6; /* class, TTL */
1822 GETSHORT(rdlen2, p1);
1823
1824 if (type2 == T_CNAME)
1825 {
1826 if (!expand_workspace(&targets, &target_sz, targetidx))
1827 return STAT_BOGUS;
1828
1829 targets[targetidx++] = p1; /* pointer to target name */
1830 }
1831
1832 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1833 return STAT_BOGUS;
1834 }
1835
Simon Kelley0fc2f312014-01-08 10:26:58 +00001836 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001837 {
Simon Kelley91421cb2018-10-18 19:21:55 +01001838 if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
1839 return STAT_BOGUS;
1840
1841 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001842 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001843
1844 GETSHORT(type1, p1);
1845 GETSHORT(class1, p1);
1846 p1 += 4; /* TTL */
1847 GETSHORT(rdlen1, p1);
1848
1849 /* Don't try and validate RRSIGs! */
Simon Kelleya6004d72017-10-25 17:48:19 +01001850 if (type1 == T_RRSIG)
1851 continue;
1852
1853 /* Check if we've done this RRset already */
1854 for (p2 = ans_start, j = 0; j < i; j++)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001855 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001856 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1857 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001858
Simon Kelleya6004d72017-10-25 17:48:19 +01001859 GETSHORT(type2, p2);
1860 GETSHORT(class2, p2);
1861 p2 += 4; /* TTL */
1862 GETSHORT(rdlen2, p2);
1863
1864 if (type2 == type1 && class2 == class1 && rc == 1)
1865 break; /* Done it before: name, type, class all match. */
1866
1867 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1868 return STAT_BOGUS;
1869 }
1870
1871 if (j != i)
1872 {
1873 /* Done already: copy the validation status */
Simon Kelley373e9172017-12-01 22:40:56 +00001874 if (i < ntohs(header->ancount))
1875 daemon->rr_status[i] = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +01001876 }
1877 else
1878 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001879 /* Not done, validate now */
Simon Kelleya6004d72017-10-25 17:48:19 +01001880 int sigcnt, rrcnt;
1881 char *wildname;
1882
1883 if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
1884 return STAT_BOGUS;
1885
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001886 /* 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 +01001887 if (sigcnt == 0)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001888 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001889 if (check_unsigned)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001890 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001891 rc = zone_status(name, class1, keyname, now);
1892 if (rc == STAT_SECURE)
1893 rc = STAT_BOGUS;
1894 if (class)
1895 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001896 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001897 else
1898 rc = STAT_INSECURE;
Simon Kelley5107ace2014-02-23 10:48:32 +00001899
Simon Kelleya6004d72017-10-25 17:48:19 +01001900 if (rc != STAT_INSECURE)
1901 return rc;
1902 }
1903 else
1904 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001905 /* explore_rrset() gives us key name from sigs in keyname.
1906 Can't overwrite name here. */
1907 strcpy(daemon->workspacename, keyname);
1908 rc = zone_status(daemon->workspacename, class1, keyname, now);
Simon Kelleya6004d72017-10-25 17:48:19 +01001909
1910 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001911 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001912 if (class)
Simon Kelley3b799c82015-12-17 16:58:04 +00001913 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley9a31b682015-12-15 10:20:39 +00001914 return rc;
Simon Kelleya6004d72017-10-25 17:48:19 +01001915 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001916
Simon Kelleya6004d72017-10-25 17:48:19 +01001917 /* Zone is insecure, don't need to validate RRset */
1918 if (rc == STAT_SECURE)
Simon Kelley9a31b682015-12-15 10:20:39 +00001919 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001920 rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
1921 rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
1922
1923 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
1924 {
1925 if (class)
1926 *class = class1; /* Class for DS or DNSKEY */
1927 return rc;
1928 }
1929
Simon Kelley9a31b682015-12-15 10:20:39 +00001930 /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
Simon Kelleya6004d72017-10-25 17:48:19 +01001931
1932 /* Note that RR is validated */
Simon Kelley373e9172017-12-01 22:40:56 +00001933 if (i < ntohs(header->ancount))
1934 daemon->rr_status[i] = 1;
Simon Kelleya6004d72017-10-25 17:48:19 +01001935
Simon Kelley9a31b682015-12-15 10:20:39 +00001936 /* Note if we've validated either the answer to the question
1937 or the target of a CNAME. Any not noted will need NSEC or
1938 to be in unsigned space. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001939 for (j = 0; j <targetidx; j++)
1940 if ((p2 = targets[j]))
1941 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001942 int rc1;
1943 if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001944 return STAT_BOGUS; /* bad packet */
1945
Simon Kelleya6004d72017-10-25 17:48:19 +01001946 if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
Simon Kelley9a31b682015-12-15 10:20:39 +00001947 targets[j] = NULL;
1948 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001949
1950 /* An attacker replay a wildcard answer with a different
1951 answer and overlay a genuine RR. To prove this
1952 hasn't happened, the answer must prove that
1953 the genuine record doesn't exist. Check that here.
1954 Note that we may not yet have validated the NSEC/NSEC3 RRsets.
1955 That's not a problem since if the RRsets later fail
1956 we'll return BOGUS then. */
1957 if (rc == STAT_SECURE_WILDCARD &&
1958 !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001959 return STAT_BOGUS;
Simon Kelleya6004d72017-10-25 17:48:19 +01001960
1961 rc = STAT_SECURE;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001962 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001963 }
1964 }
1965
Simon Kelleya6004d72017-10-25 17:48:19 +01001966 if (rc == STAT_INSECURE)
1967 secure = STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001968 }
1969
Simon Kelley9a31b682015-12-15 10:20:39 +00001970 /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
Simon Kelley7f008432018-04-15 20:01:49 +01001971 if (secure == STAT_SECURE)
Simon Kelley4e72fec2018-04-11 22:49:31 +01001972 for (j = 0; j <targetidx; j++)
1973 if ((p2 = targets[j]))
1974 {
1975 if (neganswer)
1976 *neganswer = 1;
1977
1978 if (!extract_name(header, plen, &p2, name, 1, 10))
1979 return STAT_BOGUS; /* bad packet */
1980
1981 /* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
1982
1983 /* For anything other than a DS record, this situation is OK if either
1984 the answer is in an unsigned zone, or there's a NSEC records. */
1985 if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
1986 {
1987 /* Empty DS without NSECS */
1988 if (qtype == T_DS)
1989 return STAT_BOGUS;
1990
1991 if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
1992 {
1993 if (class)
1994 *class = qclass; /* Class for NEED_DS or NEED_KEY */
1995 return rc;
1996 }
1997
1998 return STAT_BOGUS; /* signed zone, no NSECs */
1999 }
2000 }
Simon Kelley9a31b682015-12-15 10:20:39 +00002001
Simon Kelleya6004d72017-10-25 17:48:19 +01002002 return secure;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002003}
2004
2005
Giovanni Bajo3471f182012-04-25 17:49:16 +02002006/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002007int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02002008{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002009 if (alg == 1)
2010 {
2011 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
2012 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002013 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002014 }
2015 else
2016 {
Simon Kelley1633e302014-02-10 16:42:46 +00002017 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002018 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002019
Simon Kelley0fc2f312014-01-08 10:26:58 +00002020 for (i = 0; i < keylen; ++i)
2021 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002022
Simon Kelley0fc2f312014-01-08 10:26:58 +00002023 ac += (ac >> 16) & 0xffff;
2024 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002025 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002026}
2027
Simon Kelley33702ab2015-12-28 23:17:15 +00002028size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
Simon Kelleye1791f32018-10-06 23:23:23 +01002029 int type, int edns_pktsz)
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002030{
2031 unsigned char *p;
Simon Kelleya77cec82015-05-08 16:25:38 +01002032 size_t ret;
Giovanni Bajo0304d282012-05-02 03:29:52 +02002033
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002034 header->qdcount = htons(1);
2035 header->ancount = htons(0);
2036 header->nscount = htons(0);
2037 header->arcount = htons(0);
2038
2039 header->hb3 = HB3_RD;
2040 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002041 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2042 this allows it to select auth servers when one is returning bad data. */
2043 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002044
2045 /* ID filled in later */
2046
2047 p = (unsigned char *)(header+1);
2048
Simon Kelley0549c732017-09-25 18:17:11 +01002049 p = do_rfc1035_name(p, name, NULL);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002050 *p++ = 0;
2051 PUTSHORT(type, p);
2052 PUTSHORT(class, p);
2053
Simon Kelleya77cec82015-05-08 16:25:38 +01002054 ret = add_do_bit(header, p - (unsigned char *)header, end);
2055
Simon Kelley5bb88f02015-12-21 16:23:47 +00002056 if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
Simon Kelleya77cec82015-05-08 16:25:38 +01002057 PUTSHORT(edns_pktsz, p);
2058
2059 return ret;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002060}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002061
2062unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2063{
2064 int q;
2065 unsigned int len;
2066 unsigned char *p = (unsigned char *)(header+1);
2067 const struct nettle_hash *hash;
2068 void *ctx;
2069 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002070
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002071 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2072 return NULL;
2073
2074 for (q = ntohs(header->qdcount); q != 0; q--)
2075 {
Simon Kelley394ff492015-03-29 22:17:14 +01002076 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002077 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002078
2079 len = to_wire(name);
2080 hash->update(ctx, len, (unsigned char *)name);
2081 /* CRC the class and type as well */
2082 hash->update(ctx, 4, p);
2083
2084 p += 4;
2085 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002086 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002087 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002088
2089 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002090 return digest;
2091}
2092
Simon Kelley0fc2f312014-01-08 10:26:58 +00002093#endif /* HAVE_DNSSEC */