blob: db5c2d11c8d0a5323f087be4841838c92b07ac96 [file] [log] [blame]
Giovanni Bajo8d41ebd2012-05-05 00:48:12 +02001/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
Simon Kelley2a8710a2020-01-05 16:40:06 +00002 and Copyright (c) 2012-2020 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 Kelleyae7a3b92019-09-03 14:40:47 +0100189static int is_check_date(unsigned long curtime)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000190{
Simon Kelleye98bd522014-03-28 20:41:23 +0000191 /* Checking timestamps may be temporarily disabled */
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000192
193 /* If the current time if _before_ the timestamp
194 on our persistent timestamp file, then assume the
195 time if not yet correct, and don't check the
196 key timestamps. As soon as the current time is
197 later then the timestamp, update the timestamp
198 and start checking keys */
199 if (daemon->timestamp_file)
200 {
Kevin Darbyshire-Bryant34b5d192015-07-27 19:34:23 +0100201 if (daemon->back_to_the_future == 0 && difftime(timestamp_time, curtime) <= 0)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000202 {
Vladislav Grishenko4583dd92017-05-03 23:16:51 +0100203 if (utimes(daemon->timestamp_file, NULL) != 0)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000204 my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
205
Kevin Darbyshire-Bryant06093a92016-07-11 21:03:27 +0100206 my_syslog(LOG_INFO, _("system time considered valid, now checking DNSSEC signature timestamps."));
Kevin Darbyshire-Bryant34b5d192015-07-27 19:34:23 +0100207 daemon->back_to_the_future = 1;
Kevin Darbyshire-Bryant06093a92016-07-11 21:03:27 +0100208 daemon->dnssec_no_time_check = 0;
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000209 queue_event(EVENT_RELOAD); /* purge cache */
210 }
211
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100212 return daemon->back_to_the_future;
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000213 }
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100214 else
215 return !daemon->dnssec_no_time_check;
216}
217
218/* Check whether today/now is between date_start and date_end */
219static int check_date_range(unsigned long curtime, u32 date_start, u32 date_end)
220{
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000221 /* We must explicitly check against wanted values, because of SERIAL_UNDEF */
222 return serial_compare_32(curtime, date_start) == SERIAL_GT
223 && serial_compare_32(curtime, date_end) == SERIAL_LT;
224}
225
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000226/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
227 data, pointed to by *p, should be used raw. */
Simon Kelley094b5c32014-12-21 16:11:52 +0000228static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000229 unsigned char **p, u16 **desc)
230{
231 int d = **desc;
232
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000233 /* No more data needs mangling */
234 if (d == (u16)-1)
Simon Kelley094b5c32014-12-21 16:11:52 +0000235 {
236 /* If there's more data than we have space for, just return what fits,
237 we'll get called again for more chunks */
238 if (end - *p > bufflen)
239 {
240 memcpy(buff, *p, bufflen);
241 *p += bufflen;
242 return bufflen;
243 }
244
245 return 0;
246 }
247
248 (*desc)++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000249
Simon Kelley394ff492015-03-29 22:17:14 +0100250 if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000251 /* domain-name, canonicalise */
252 return to_wire(buff);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000253 else
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000254 {
255 /* plain data preceding a domain-name, don't run off the end of the data */
256 if ((end - *p) < d)
257 d = end - *p;
258
259 if (d != 0)
260 {
261 memcpy(buff, *p, d);
262 *p += d;
263 }
264
265 return d;
266 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000267}
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000268
269/* Bubble sort the RRset into the canonical order.
270 Note that the byte-streams from two RRs may get unsynced: consider
271 RRs which have two domain-names at the start and then other data.
272 The domain-names may have different lengths in each RR, but sort equal
273
274 ------------
275 |abcde|fghi|
276 ------------
277 |abcd|efghi|
278 ------------
279
280 leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
281*/
282
Simon Kelleye5412452018-01-06 22:16:31 +0000283static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
284 unsigned char **rrset, char *buff1, char *buff2)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000285{
Simon Kelleye5412452018-01-06 22:16:31 +0000286 int swap, quit, i, j;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000287
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000288 do
289 {
290 for (swap = 0, i = 0; i < rrsetidx-1; i++)
291 {
292 int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
293 u16 *dp1, *dp2;
294 unsigned char *end1, *end2;
Simon Kelley5107ace2014-02-23 10:48:32 +0000295 /* Note that these have been determined to be OK previously,
296 so we don't need to check for NULL return here. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000297 unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
298 unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
299
300 p1 += 8; /* skip class, type, ttl */
301 GETSHORT(rdlen1, p1);
302 end1 = p1 + rdlen1;
303
304 p2 += 8; /* skip class, type, ttl */
305 GETSHORT(rdlen2, p2);
306 end2 = p2 + rdlen2;
307
308 dp1 = dp2 = rr_desc;
309
Simon Kelley1486a9c2014-01-10 11:39:14 +0000310 for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000311 {
Simon Kelley1486a9c2014-01-10 11:39:14 +0000312 if (left1 != 0)
313 memmove(buff1, buff1 + len1 - left1, left1);
314
Simon Kelleycbe379a2015-04-21 22:57:06 +0100315 if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000316 {
317 quit = 1;
318 len1 = end1 - p1;
319 memcpy(buff1 + left1, p1, len1);
320 }
321 len1 += left1;
322
Simon Kelley1486a9c2014-01-10 11:39:14 +0000323 if (left2 != 0)
324 memmove(buff2, buff2 + len2 - left2, left2);
325
Simon Kelleycbe379a2015-04-21 22:57:06 +0100326 if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000327 {
328 quit = 1;
329 len2 = end2 - p2;
330 memcpy(buff2 + left2, p2, len2);
331 }
332 len2 += left2;
333
334 if (len1 > len2)
Simon Kelley1486a9c2014-01-10 11:39:14 +0000335 left1 = len1 - len2, left2 = 0, len = len2;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000336 else
Simon Kelley1486a9c2014-01-10 11:39:14 +0000337 left2 = len2 - len1, left1 = 0, len = len1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000338
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000339 rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000340
Simon Kelley4619d942014-01-16 19:53:06 +0000341 if (rc > 0 || (rc == 0 && quit && len1 > len2))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000342 {
343 unsigned char *tmp = rrset[i+1];
344 rrset[i+1] = rrset[i];
345 rrset[i] = tmp;
346 swap = quit = 1;
347 }
Simon Kelleye5412452018-01-06 22:16:31 +0000348 else if (rc == 0 && quit && len1 == len2)
349 {
350 /* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
351 for (j = i+1; j < rrsetidx-1; j++)
352 rrset[j] = rrset[j+1];
353 rrsetidx--;
354 i--;
355 }
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000356 else if (rc < 0)
357 quit = 1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000358 }
359 }
360 } while (swap);
Simon Kelleye5412452018-01-06 22:16:31 +0000361
362 return rrsetidx;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000363}
364
Simon Kelley9a31b682015-12-15 10:20:39 +0000365static unsigned char **rrset = NULL, **sigs = NULL;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000366
Josh Soref730c6742017-02-06 16:14:04 +0000367/* Get pointers to RRset members and signature(s) for same.
Simon Kelley9a31b682015-12-15 10:20:39 +0000368 Check signatures, and return keyname associated in keyname. */
369static int explore_rrset(struct dns_header *header, size_t plen, int class, int type,
370 char *name, char *keyname, int *sigcnt, int *rrcnt)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000371{
Simon Kelley9a31b682015-12-15 10:20:39 +0000372 static int rrset_sz = 0, sig_sz = 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000373 unsigned char *p;
Simon Kelley9a31b682015-12-15 10:20:39 +0000374 int rrsetidx, sigidx, j, rdlen, res;
Simon Kelley9a31b682015-12-15 10:20:39 +0000375 int gotkey = 0;
376
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000377 if (!(p = skip_questions(header, plen)))
Simon Kelley05299fd2019-07-15 22:04:20 +0100378 return 0;
Simon Kelley5ada8882014-01-09 22:25:03 +0000379
Simon Kelley9a31b682015-12-15 10:20:39 +0000380 /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000381 for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
382 j != 0; j--)
383 {
384 unsigned char *pstart, *pdata;
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000385 int stype, sclass, type_covered;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000386
387 pstart = p;
388
389 if (!(res = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley05299fd2019-07-15 22:04:20 +0100390 return 0; /* bad packet */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000391
392 GETSHORT(stype, p);
393 GETSHORT(sclass, p);
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100394
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000395 pdata = p;
396
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100397 p += 4; /* TTL */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000398 GETSHORT(rdlen, p);
399
Simon Kelleye7829ae2014-01-22 22:21:51 +0000400 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley9a31b682015-12-15 10:20:39 +0000401 return 0;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000402
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000403 if (res == 1 && sclass == class)
404 {
405 if (stype == type)
406 {
Simon Kelley613ad152014-02-25 23:02:28 +0000407 if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
Simon Kelley9a31b682015-12-15 10:20:39 +0000408 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +0000409
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000410 rrset[rrsetidx++] = pstart;
411 }
412
413 if (stype == T_RRSIG)
414 {
Simon Kelley613ad152014-02-25 23:02:28 +0000415 if (rdlen < 18)
Simon Kelley9a31b682015-12-15 10:20:39 +0000416 return 0; /* bad packet */
Simon Kelley613ad152014-02-25 23:02:28 +0000417
418 GETSHORT(type_covered, p);
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000419 p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
Simon Kelley613ad152014-02-25 23:02:28 +0000420
Simon Kelley9a31b682015-12-15 10:20:39 +0000421 if (gotkey)
422 {
423 /* If there's more than one SIG, ensure they all have same keyname */
424 if (extract_name(header, plen, &p, keyname, 0, 0) != 1)
425 return 0;
426 }
427 else
428 {
429 gotkey = 1;
430
431 if (!extract_name(header, plen, &p, keyname, 1, 0))
432 return 0;
433
434 /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
435 the name of the zone containing the RRset. We can't tell that
436 for certain, but we can check that the RRset name is equal to
437 or encloses the signers name, which should be enough to stop
438 an attacker using signatures made with the key of an unrelated
439 zone he controls. Note that the root key is always allowed. */
440 if (*keyname != 0)
441 {
442 char *name_start;
443 for (name_start = name; !hostname_isequal(name_start, keyname); )
444 if ((name_start = strchr(name_start, '.')))
445 name_start++; /* chop a label off and try again */
446 else
447 return 0;
448 }
449 }
450
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000451
452 if (type_covered == type)
Simon Kelley613ad152014-02-25 23:02:28 +0000453 {
454 if (!expand_workspace(&sigs, &sig_sz, sigidx))
Simon Kelley9a31b682015-12-15 10:20:39 +0000455 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +0000456
457 sigs[sigidx++] = pdata;
458 }
459
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100460 p = pdata + 6; /* restore for ADD_RDLEN */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000461 }
462 }
Simon Kelley613ad152014-02-25 23:02:28 +0000463
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000464 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley9a31b682015-12-15 10:20:39 +0000465 return 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000466 }
467
Simon Kelley9a31b682015-12-15 10:20:39 +0000468 *sigcnt = sigidx;
469 *rrcnt = rrsetidx;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000470
Simon Kelley9a31b682015-12-15 10:20:39 +0000471 return 1;
472}
473
474/* Validate a single RRset (class, type, name) in the supplied DNS reply
475 Return code:
476 STAT_SECURE if it validates.
477 STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
478 (In this case *wildcard_out points to the "body" of the wildcard within name.)
479 STAT_BOGUS signature is wrong, bad packet.
480 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
481 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
482
Simon Kelley2dbba342015-12-16 13:41:58 +0000483 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 +0000484 otherwise find the key in the cache.
485
Simon Kelley2dbba342015-12-16 13:41:58 +0000486 Name is unchanged on exit. keyname is used as workspace and trashed.
Simon Kelley9a31b682015-12-15 10:20:39 +0000487
488 Call explore_rrset first to find and count RRs and sigs.
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100489
490 ttl_out is the floor on TTL, based on TTL and orig_ttl and expiration of sig used to validate.
Simon Kelley9a31b682015-12-15 10:20:39 +0000491*/
492static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, int sigidx, int rrsetidx,
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100493 char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen,
494 int algo_in, int keytag_in, unsigned long *ttl_out)
Simon Kelley9a31b682015-12-15 10:20:39 +0000495{
496 unsigned char *p;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100497 int rdlen, j, name_labels, algo, labels, key_tag;
Simon Kelley9a31b682015-12-15 10:20:39 +0000498 struct crec *crecp = NULL;
Simon Kelleyc2bcd1e2015-12-15 17:25:21 +0000499 u16 *rr_desc = rrfilter_desc(type);
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100500 u32 sig_expiration, sig_inception;
501
502 unsigned long curtime = time(0);
503 int time_check = is_check_date(curtime);
504
Simon Kelley9a31b682015-12-15 10:20:39 +0000505 if (wildcard_out)
506 *wildcard_out = NULL;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000507
Simon Kelley9a31b682015-12-15 10:20:39 +0000508 name_labels = count_labels(name); /* For 4035 5.3.2 check */
509
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000510 /* Sort RRset records into canonical order.
Simon Kelleyd3873802014-02-23 16:20:46 +0000511 Note that at this point keyname and daemon->workspacename buffs are
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000512 unused, and used as workspace by the sort. */
Simon Kelleye5412452018-01-06 22:16:31 +0000513 rrsetidx = sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000514
515 /* Now try all the sigs to try and find one which validates */
516 for (j = 0; j <sigidx; j++)
517 {
Simon Kelleyd3873802014-02-23 16:20:46 +0000518 unsigned char *psav, *sig, *digest;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000519 int i, wire_len, sig_len;
520 const struct nettle_hash *hash;
521 void *ctx;
Simon Kelleyd3873802014-02-23 16:20:46 +0000522 char *name_start;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100523 u32 nsigttl, ttl, orig_ttl;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000524
525 p = sigs[j];
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100526 GETLONG(ttl, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000527 GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000528 psav = p;
529
Simon Kelley5ada8882014-01-09 22:25:03 +0000530 p += 2; /* type_covered - already checked */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000531 algo = *p++;
532 labels = *p++;
533 GETLONG(orig_ttl, p);
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000534 GETLONG(sig_expiration, p);
535 GETLONG(sig_inception, p);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000536 GETSHORT(key_tag, p);
537
Simon Kelley394ff492015-03-29 22:17:14 +0100538 if (!extract_name(header, plen, &p, keyname, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +0000539 return STAT_BOGUS;
Simon Kelleyd3873802014-02-23 16:20:46 +0000540
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100541 if ((time_check && !check_date_range(curtime, sig_inception, sig_expiration)) ||
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000542 labels > name_labels ||
543 !(hash = hash_find(algo_digest_name(algo))) ||
Simon Kelleye7829ae2014-01-22 22:21:51 +0000544 !hash_init(hash, &ctx, &digest))
545 continue;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100546
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000547 /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
548 if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
549 return STAT_NEED_KEY;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100550
551 if (ttl_out)
552 {
553 /* 4035 5.3.3 rules on TTLs */
554 if (orig_ttl < ttl)
555 ttl = orig_ttl;
556
557 if (time_check && difftime(sig_expiration, curtime) < ttl)
558 ttl = difftime(sig_expiration, curtime);
559
560 *ttl_out = ttl;
561 }
562
Simon Kelley86bec2d2014-01-13 21:31:20 +0000563 sig = p;
564 sig_len = rdlen - (p - psav);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000565
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000566 nsigttl = htonl(orig_ttl);
567
Simon Kelley86bec2d2014-01-13 21:31:20 +0000568 hash->update(ctx, 18, psav);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000569 wire_len = to_wire(keyname);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000570 hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000571 from_wire(keyname);
572
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000573 for (i = 0; i < rrsetidx; ++i)
574 {
575 int seg;
576 unsigned char *end, *cp;
577 u16 len, *dp;
Simon Kelleyd3873802014-02-23 16:20:46 +0000578
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000579 p = rrset[i];
Simon Kelleye5412452018-01-06 22:16:31 +0000580
Simon Kelley394ff492015-03-29 22:17:14 +0100581 if (!extract_name(header, plen, &p, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +0000582 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000583
Simon Kelleyd3873802014-02-23 16:20:46 +0000584 name_start = name;
585
Simon Kelley5ada8882014-01-09 22:25:03 +0000586 /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
587 if (labels < name_labels)
588 {
589 int k;
590 for (k = name_labels - labels; k != 0; k--)
Simon Kelleyfbc52052014-12-23 15:46:08 +0000591 {
592 while (*name_start != '.' && *name_start != 0)
593 name_start++;
Simon Kelley0b1008d2014-12-27 15:33:32 +0000594 if (k != 1 && *name_start == '.')
Simon Kelleyfbc52052014-12-23 15:46:08 +0000595 name_start++;
596 }
597
598 if (wildcard_out)
599 *wildcard_out = name_start+1;
600
Simon Kelley5ada8882014-01-09 22:25:03 +0000601 name_start--;
602 *name_start = '*';
603 }
604
605 wire_len = to_wire(name_start);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000606 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
607 hash->update(ctx, 4, p); /* class and type */
608 hash->update(ctx, 4, (unsigned char *)&nsigttl);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000609
610 p += 8; /* skip class, type, ttl */
611 GETSHORT(rdlen, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000612 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000613 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000614
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000615 end = p + rdlen;
616
Simon Kelleycbe379a2015-04-21 22:57:06 +0100617 /* canonicalise rdata and calculate length of same, use name buffer as workspace.
618 Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000619 cp = p;
620 dp = rr_desc;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100621 for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000622 len += end - cp;
623 len = htons(len);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000624 hash->update(ctx, 2, (unsigned char *)&len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000625
626 /* Now canonicalise again and digest. */
627 cp = p;
628 dp = rr_desc;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100629 while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000630 hash->update(ctx, seg, (unsigned char *)name);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000631 if (cp != end)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000632 hash->update(ctx, end - cp, cp);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000633 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000634
635 hash->digest(ctx, hash->digest_size, digest);
636
Simon Kelley5ada8882014-01-09 22:25:03 +0000637 /* namebuff used for workspace above, restore to leave unchanged on exit */
638 p = (unsigned char*)(rrset[0]);
Simon Kelley394ff492015-03-29 22:17:14 +0100639 extract_name(header, plen, &p, name, 1, 0);
Simon Kelley5ada8882014-01-09 22:25:03 +0000640
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000641 if (key)
642 {
643 if (algo_in == algo && keytag_in == key_tag &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000644 verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000645 return STAT_SECURE;
646 }
647 else
648 {
649 /* iterate through all possible keys 4035 5.3.1 */
650 for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
Simon Kelleycc921df2019-01-02 22:48:59 +0000651 if (crecp->addr.key.algo == algo &&
652 crecp->addr.key.keytag == key_tag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000653 crecp->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000654 verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5107ace2014-02-23 10:48:32 +0000655 return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000656 }
657 }
658
659 return STAT_BOGUS;
660}
661
Simon Kelley2dbba342015-12-16 13:41:58 +0000662
Simon Kelley0fc2f312014-01-08 10:26:58 +0000663/* The DNS packet is expected to contain the answer to a DNSKEY query.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000664 Put all DNSKEYs in the answer which are valid into the cache.
665 return codes:
Simon Kelley3b799c82015-12-17 16:58:04 +0000666 STAT_OK Done, key(s) in cache.
667 STAT_BOGUS No DNSKEYs found, which can be validated with DS,
668 or self-sign for DNSKEY RRset is not valid, bad packet.
669 STAT_NEED_DS DS records to validate a key not found, name in keyname
670 STAT_NEED_KEY DNSKEY records to validate a key not found, name in keyname
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000671*/
672int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
673{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000674 unsigned char *psave, *p = (unsigned char *)(header+1);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000675 struct crec *crecp, *recp1;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100676 int rc, j, qtype, qclass, rdlen, flags, algo, valid, keytag;
677 unsigned long ttl, sig_ttl;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000678 struct blockdata *key;
Simon Kelleycc921df2019-01-02 22:48:59 +0000679 union all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000680
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000681 if (ntohs(header->qdcount) != 1 ||
Simon Kelley19b0e3b2019-10-12 21:54:37 +0100682 RCODE(header) == SERVFAIL || RCODE(header) == REFUSED ||
Simon Kelley394ff492015-03-29 22:17:14 +0100683 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +0000684 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000685
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000686 GETSHORT(qtype, p);
687 GETSHORT(qclass, p);
688
Simon Kelley97e618a2015-01-07 21:55:43 +0000689 if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000690 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000691
Simon Kelleyb8eac192014-02-27 14:30:03 +0000692 /* See if we have cached a DS record which validates this key */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000693 if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
694 {
695 strcpy(keyname, name);
696 return STAT_NEED_DS;
697 }
Simon Kelleyb8eac192014-02-27 14:30:03 +0000698
Simon Kelley0fc2f312014-01-08 10:26:58 +0000699 /* NOTE, we need to find ONE DNSKEY which matches the DS */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000700 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000701 {
702 /* Ensure we have type, class TTL and length */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000703 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +0000704 return STAT_BOGUS; /* bad packet */
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000705
706 GETSHORT(qtype, p);
707 GETSHORT(qclass, p);
708 GETLONG(ttl, p);
709 GETSHORT(rdlen, p);
Simon Kelley6f468102014-01-26 23:39:17 +0000710
Simon Kelley0fc2f312014-01-08 10:26:58 +0000711 if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000712 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000713
Simon Kelley6f468102014-01-26 23:39:17 +0000714 if (qclass != class || qtype != T_DNSKEY || rc == 2)
715 {
716 p += rdlen;
717 continue;
718 }
719
Simon Kelley0fc2f312014-01-08 10:26:58 +0000720 psave = p;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000721
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000722 GETSHORT(flags, p);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000723 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000724 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000725 algo = *p++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000726 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000727 key = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000728
Simon Kelleye7829ae2014-01-22 22:21:51 +0000729 /* key must have zone key flag set */
730 if (flags & 0x100)
731 key = blockdata_alloc((char*)p, rdlen - 4);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000732
733 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000734
Simon Kelley0fc2f312014-01-08 10:26:58 +0000735 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000736 {
737 if (key)
738 blockdata_free(key);
Simon Kelley87070192014-03-01 20:48:24 +0000739 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000740 }
741
Simon Kelleye7829ae2014-01-22 22:21:51 +0000742 /* No zone key flag or malloc failure */
743 if (!key)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000744 continue;
745
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000746 for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000747 {
748 void *ctx;
749 unsigned char *digest, *ds_digest;
750 const struct nettle_hash *hash;
Simon Kelley9a31b682015-12-15 10:20:39 +0000751 int sigcnt, rrcnt;
752
Simon Kelleycc921df2019-01-02 22:48:59 +0000753 if (recp1->addr.ds.algo == algo &&
754 recp1->addr.ds.keytag == keytag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000755 recp1->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000756 (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
Simon Kelley86bec2d2014-01-13 21:31:20 +0000757 hash_init(hash, &ctx, &digest))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000758
Simon Kelley86bec2d2014-01-13 21:31:20 +0000759 {
760 int wire_len = to_wire(name);
761
762 /* Note that digest may be different between DSs, so
763 we can't move this outside the loop. */
764 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
765 hash->update(ctx, (unsigned int)rdlen, psave);
766 hash->digest(ctx, hash->digest_size, digest);
767
768 from_wire(name);
769
Simon Kelley9a31b682015-12-15 10:20:39 +0000770 if (!(recp1->flags & F_NEG) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000771 recp1->addr.ds.keylen == (int)hash->digest_size &&
772 (ds_digest = blockdata_retrieve(recp1->addr.ds.keydata, recp1->addr.ds.keylen, NULL)) &&
773 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
Simon Kelley9a31b682015-12-15 10:20:39 +0000774 explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
775 sigcnt != 0 && rrcnt != 0 &&
776 validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100777 NULL, key, rdlen - 4, algo, keytag, &sig_ttl) == STAT_SECURE)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000778 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000779 valid = 1;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000780 break;
781 }
782 }
783 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000784 blockdata_free(key);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000785 }
786
787 if (valid)
788 {
Simon Kelley93be5b12015-12-15 12:04:40 +0000789 /* DNSKEY RRset determined to be OK, now cache it. */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000790 cache_start_insert();
791
792 p = skip_questions(header, plen);
793
794 for (j = ntohs(header->ancount); j != 0; j--)
795 {
796 /* Ensure we have type, class TTL and length */
797 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +0000798 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000799
800 GETSHORT(qtype, p);
801 GETSHORT(qclass, p);
802 GETLONG(ttl, p);
803 GETSHORT(rdlen, p);
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100804
805 /* TTL may be limited by sig. */
806 if (sig_ttl < ttl)
807 ttl = sig_ttl;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000808
809 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000810 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000811
Simon Kelley8d718cb2014-02-03 16:27:37 +0000812 if (qclass == class && rc == 1)
Simon Kelleye7829ae2014-01-22 22:21:51 +0000813 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000814 psave = p;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000815
Simon Kelley8d718cb2014-02-03 16:27:37 +0000816 if (qtype == T_DNSKEY)
817 {
818 if (rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000819 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000820
821 GETSHORT(flags, p);
822 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000823 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000824 algo = *p++;
825 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
826
Simon Kelley8d718cb2014-02-03 16:27:37 +0000827 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
828 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000829 a.key.keylen = rdlen - 4;
830 a.key.keydata = key;
831 a.key.algo = algo;
832 a.key.keytag = keytag;
833 a.key.flags = flags;
Simon Kelleyab194ed2019-01-01 01:35:30 +0000834
835 if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK))
Simon Kelley93be5b12015-12-15 12:04:40 +0000836 {
837 blockdata_free(key);
838 return STAT_BOGUS;
839 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000840 else
841 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000842 a.log.keytag = keytag;
843 a.log.algo = algo;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100844 if (algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000845 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000846 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000847 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
Simon Kelley8d718cb2014-02-03 16:27:37 +0000848 }
849 }
850 }
Simon Kelley93be5b12015-12-15 12:04:40 +0000851
Simon Kelley8d718cb2014-02-03 16:27:37 +0000852 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000853 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000854
Simon Kelleye7829ae2014-01-22 22:21:51 +0000855 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000856 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000857 }
858
Simon Kelley0fc2f312014-01-08 10:26:58 +0000859 /* commit cache insert. */
860 cache_end_insert();
Simon Kelley9a31b682015-12-15 10:20:39 +0000861 return STAT_OK;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000862 }
863
Simon Kelley25cf5e32015-01-09 15:53:03 +0000864 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
Simon Kelley0fc2f312014-01-08 10:26:58 +0000865 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000866}
Simon Kelley0fc2f312014-01-08 10:26:58 +0000867
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000868/* The DNS packet is expected to contain the answer to a DS query
869 Put all DSs in the answer which are valid into the cache.
Simon Kelley9a31b682015-12-15 10:20:39 +0000870 Also handles replies which prove that there's no DS at this location,
871 either because the zone is unsigned or this isn't a zone cut. These are
872 cached too.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000873 return codes:
Simon Kelley9a31b682015-12-15 10:20:39 +0000874 STAT_OK At least one valid DS found and in cache.
Simon Kelley97e618a2015-01-07 21:55:43 +0000875 STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000876 STAT_NEED_KEY DNSKEY records to validate a DS not found, name in keyname
Simon Kelley9a31b682015-12-15 10:20:39 +0000877 STAT_NEED_DS DS record needed.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000878*/
879
880int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
881{
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000882 unsigned char *p = (unsigned char *)(header+1);
Simon Kelleyfef2f1c2019-08-29 21:59:00 +0100883 int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0;
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000884 int aclass, atype, rdlen;
885 unsigned long ttl;
Simon Kelleycc921df2019-01-02 22:48:59 +0000886 union all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000887
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000888 if (ntohs(header->qdcount) != 1 ||
Simon Kelleyb8eac192014-02-27 14:30:03 +0000889 !(p = skip_name(p, header, plen, 4)))
Simon Kelley87070192014-03-01 20:48:24 +0000890 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000891
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000892 GETSHORT(qtype, p);
893 GETSHORT(qclass, p);
894
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000895 if (qtype != T_DS || qclass != class)
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000896 rc = STAT_BOGUS;
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000897 else
Simon Kelleyfef2f1c2019-08-29 21:59:00 +0100898 rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl);
Simon Kelley97e618a2015-01-07 21:55:43 +0000899
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000900 if (rc == STAT_INSECURE)
Simon Kelley7f008432018-04-15 20:01:49 +0100901 {
Kevin Darbyshire-Bryantc65b77c2019-05-11 17:05:23 +0000902 my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
Simon Kelley7f008432018-04-15 20:01:49 +0100903 rc = STAT_BOGUS;
904 }
905
Simon Kelleyb8eac192014-02-27 14:30:03 +0000906 p = (unsigned char *)(header+1);
Simon Kelley394ff492015-03-29 22:17:14 +0100907 extract_name(header, plen, &p, name, 1, 4);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000908 p += 4; /* qtype, qclass */
909
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000910 /* If the key needed to validate the DS is on the same domain as the DS, we'll
911 loop getting nowhere. Stop that now. This can happen of the DS answer comes
912 from the DS's zone, and not the parent zone. */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000913 if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
Simon Kelleyb8eac192014-02-27 14:30:03 +0000914 {
Simon Kelley25cf5e32015-01-09 15:53:03 +0000915 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
Simon Kelley97e618a2015-01-07 21:55:43 +0000916 return STAT_BOGUS;
917 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000918
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000919 if (rc != STAT_SECURE)
920 return rc;
921
922 if (!neganswer)
Simon Kelley97e618a2015-01-07 21:55:43 +0000923 {
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000924 cache_start_insert();
925
926 for (i = 0; i < ntohs(header->ancount); i++)
927 {
928 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
929 return STAT_BOGUS; /* bad packet */
930
931 GETSHORT(atype, p);
932 GETSHORT(aclass, p);
933 GETLONG(ttl, p);
934 GETSHORT(rdlen, p);
935
936 if (!CHECK_LEN(header, p, plen, rdlen))
937 return STAT_BOGUS; /* bad packet */
938
939 if (aclass == class && atype == T_DS && rc == 1)
940 {
941 int algo, digest, keytag;
942 unsigned char *psave = p;
943 struct blockdata *key;
Simon Kelleyab194ed2019-01-01 01:35:30 +0000944
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000945 if (rdlen < 4)
946 return STAT_BOGUS; /* bad packet */
947
948 GETSHORT(keytag, p);
949 algo = *p++;
950 digest = *p++;
951
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000952 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
953 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000954 a.ds.digest = digest;
955 a.ds.keydata = key;
956 a.ds.algo = algo;
957 a.ds.keytag = keytag;
958 a.ds.keylen = rdlen - 4;
Simon Kelleyab194ed2019-01-01 01:35:30 +0000959
960 if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000961 {
962 blockdata_free(key);
963 return STAT_BOGUS;
964 }
965 else
966 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000967 a.log.keytag = keytag;
968 a.log.algo = algo;
969 a.log.digest = digest;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100970 if (ds_digest_name(digest) && algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000971 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000972 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000973 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000974 }
975 }
976
977 p = psave;
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000978 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000979 if (!ADD_RDLEN(header, p, plen, rdlen))
980 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000981 }
Simon Kelley3b799c82015-12-17 16:58:04 +0000982
983 cache_end_insert();
984
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000985 }
986 else
987 {
988 int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
Simon Kelleyfef2f1c2019-08-29 21:59:00 +0100989
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000990 if (RCODE(header) == NXDOMAIN)
991 flags |= F_NXDOMAIN;
992
Simon Kelley97e618a2015-01-07 21:55:43 +0000993 /* We only cache validated DS records, DNSSECOK flag hijacked
994 to store presence/absence of NS. */
995 if (nons)
996 flags &= ~F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000997
Simon Kelleyfef2f1c2019-08-29 21:59:00 +0100998 cache_start_insert();
Simon Kelleyb8eac192014-02-27 14:30:03 +0000999
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001000 /* Use TTL from NSEC for negative cache entries */
1001 if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
1002 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001003
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001004 cache_end_insert();
1005
Simon Kelley532246f2020-04-04 18:50:56 +01001006 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS");
Simon Kelleyb8eac192014-02-27 14:30:03 +00001007 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001008
Simon Kelley9a31b682015-12-15 10:20:39 +00001009 return STAT_OK;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001010}
1011
Simon Kelley9a31b682015-12-15 10:20:39 +00001012
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001013/* 4034 6.1 */
1014static int hostname_cmp(const char *a, const char *b)
1015{
Simon Kelleydbf72122014-01-21 14:28:02 +00001016 char *sa, *ea, *ca, *sb, *eb, *cb;
1017 unsigned char ac, bc;
1018
1019 sa = ea = (char *)a + strlen(a);
1020 sb = eb = (char *)b + strlen(b);
1021
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001022 while (1)
1023 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001024 while (sa != a && *(sa-1) != '.')
1025 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001026
Simon Kelleydbf72122014-01-21 14:28:02 +00001027 while (sb != b && *(sb-1) != '.')
1028 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001029
Simon Kelleydbf72122014-01-21 14:28:02 +00001030 ca = sa;
1031 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001032
Simon Kelleydbf72122014-01-21 14:28:02 +00001033 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001034 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001035 if (ca == ea)
1036 {
1037 if (cb == eb)
1038 break;
1039
1040 return -1;
1041 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001042
Simon Kelleydbf72122014-01-21 14:28:02 +00001043 if (cb == eb)
1044 return 1;
1045
1046 ac = (unsigned char) *ca++;
1047 bc = (unsigned char) *cb++;
1048
1049 if (ac >= 'A' && ac <= 'Z')
1050 ac += 'a' - 'A';
1051 if (bc >= 'A' && bc <= 'Z')
1052 bc += 'a' - 'A';
1053
Simon Kelley979cdf92014-01-21 16:26:41 +00001054 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001055 return -1;
1056 else if (ac != bc)
1057 return 1;
1058 }
1059
1060
1061 if (sa == a)
1062 {
1063 if (sb == b)
1064 return 0;
1065
1066 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001067 }
1068
Simon Kelleydbf72122014-01-21 14:28:02 +00001069 if (sb == b)
1070 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001071
Simon Kelley3e86d312015-12-20 20:50:05 +00001072 ea = --sa;
1073 eb = --sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001074 }
1075}
1076
Simon Kelley4fe67442018-01-19 12:26:08 +00001077static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
1078 char *workspace1_in, char *workspace2, char *name, int type, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001079{
1080 int i, rc, rdlen;
1081 unsigned char *p, *psave;
1082 int offset = (type & 0xff) >> 3;
1083 int mask = 0x80 >> (type & 0x07);
Simon Kelley97e618a2015-01-07 21:55:43 +00001084
1085 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001086 *nons = 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001087
1088 /* Find NSEC record that proves name doesn't exist */
1089 for (i = 0; i < nsec_count; i++)
1090 {
Simon Kelley4fe67442018-01-19 12:26:08 +00001091 char *workspace1 = workspace1_in;
1092 int sig_labels, name_labels;
1093
Simon Kelley5107ace2014-02-23 10:48:32 +00001094 p = nsecs[i];
Simon Kelley394ff492015-03-29 22:17:14 +01001095 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001096 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001097 p += 8; /* class, type, TTL */
1098 GETSHORT(rdlen, p);
1099 psave = p;
Simon Kelley394ff492015-03-29 22:17:14 +01001100 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001101 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001102
1103 /* If NSEC comes from wildcard expansion, use original wildcard
1104 as name for computation. */
1105 sig_labels = *labels[i];
1106 name_labels = count_labels(workspace1);
1107
1108 if (sig_labels < name_labels)
1109 {
1110 int k;
1111 for (k = name_labels - sig_labels; k != 0; k--)
1112 {
1113 while (*workspace1 != '.' && *workspace1 != 0)
1114 workspace1++;
1115 if (k != 1 && *workspace1 == '.')
1116 workspace1++;
1117 }
1118
1119 workspace1--;
1120 *workspace1 = '*';
1121 }
1122
Simon Kelley5107ace2014-02-23 10:48:32 +00001123 rc = hostname_cmp(workspace1, name);
1124
1125 if (rc == 0)
1126 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001127 /* 4035 para 5.4. Last sentence */
1128 if (type == T_NSEC || type == T_RRSIG)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001129 return 1;
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001130
Simon Kelley5107ace2014-02-23 10:48:32 +00001131 /* NSEC with the same name as the RR we're testing, check
1132 that the type in question doesn't appear in the type map */
1133 rdlen -= p - psave;
1134 /* rdlen is now length of type map, and p points to it */
1135
Simon Kelley97e618a2015-01-07 21:55:43 +00001136 /* If we can prove that there's no NS record, return that information. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001137 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
1138 *nons = 0;
Simon Kelley97e618a2015-01-07 21:55:43 +00001139
Simon Kelley9a31b682015-12-15 10:20:39 +00001140 if (rdlen >= 2 && p[0] == 0)
1141 {
1142 /* A CNAME answer would also be valid, so if there's a CNAME is should
1143 have been returned. */
1144 if ((p[2] & (0x80 >> T_CNAME)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001145 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001146
1147 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001148 DS from the wrong side of the delegation. For the root DS,
1149 this is expected. */
1150 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001151 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001152 }
1153
Simon Kelley5107ace2014-02-23 10:48:32 +00001154 while (rdlen >= 2)
1155 {
1156 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001157 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001158
1159 if (p[0] == type >> 8)
1160 {
1161 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001162 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001163 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001164
Josh Soref730c6742017-02-06 16:14:04 +00001165 break; /* finished checking */
Simon Kelley5107ace2014-02-23 10:48:32 +00001166 }
1167
1168 rdlen -= p[1];
1169 p += p[1];
1170 }
1171
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001172 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001173 }
1174 else if (rc == -1)
1175 {
1176 /* Normal case, name falls between NSEC name and next domain name,
1177 wrap around case, name falls between NSEC name (rc == -1) and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001178 if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001179 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001180 }
1181 else
1182 {
1183 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001184 if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001185 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001186 }
1187 }
1188
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001189 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001190}
1191
1192/* return digest length, or zero on error */
1193static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1194 unsigned char *salt, int salt_len, int iterations)
1195{
1196 void *ctx;
1197 unsigned char *digest;
1198 int i;
1199
1200 if (!hash_init(hash, &ctx, &digest))
1201 return 0;
1202
1203 hash->update(ctx, to_wire(in), (unsigned char *)in);
1204 hash->update(ctx, salt_len, salt);
1205 hash->digest(ctx, hash->digest_size, digest);
1206
1207 for(i = 0; i < iterations; i++)
1208 {
1209 hash->update(ctx, hash->digest_size, digest);
1210 hash->update(ctx, salt_len, salt);
1211 hash->digest(ctx, hash->digest_size, digest);
1212 }
1213
1214 from_wire(in);
1215
1216 *out = digest;
1217 return hash->digest_size;
1218}
1219
1220/* Decode base32 to first "." or end of string */
1221static int base32_decode(char *in, unsigned char *out)
1222{
Simon Kelleya857daa2014-02-24 21:01:09 +00001223 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001224 unsigned char *p = out;
1225
Simon Kelleya857daa2014-02-24 21:01:09 +00001226 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001227 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001228 if (c >= '0' && c <= '9')
1229 c -= '0';
1230 else if (c >= 'a' && c <= 'v')
1231 c -= 'a', c += 10;
1232 else if (c >= 'A' && c <= 'V')
1233 c -= 'A', c += 10;
1234 else
1235 return 0;
1236
1237 for (mask = 0x10, i = 0; i < 5; i++)
1238 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001239 if (c & mask)
1240 oc |= 1;
1241 mask = mask >> 1;
1242 if (((++on) & 7) == 0)
1243 *p++ = oc;
1244 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001245 }
1246 }
1247
1248 if ((on & 7) != 0)
1249 return 0;
1250
1251 return p - out;
1252}
1253
Simon Kelleyfbc52052014-12-23 15:46:08 +00001254static 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 +00001255 char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001256{
Simon Kelley9a31b682015-12-15 10:20:39 +00001257 int i, hash_len, salt_len, base32_len, rdlen, flags;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001258 unsigned char *p, *psave;
1259
1260 for (i = 0; i < nsec_count; i++)
1261 if ((p = nsecs[i]))
1262 {
Simon Kelley394ff492015-03-29 22:17:14 +01001263 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleyfbc52052014-12-23 15:46:08 +00001264 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
1265 return 0;
1266
1267 p += 8; /* class, type, TTL */
1268 GETSHORT(rdlen, p);
1269 psave = p;
Simon Kelley9a31b682015-12-15 10:20:39 +00001270 p++; /* algo */
1271 flags = *p++; /* flags */
1272 p += 2; /* iterations */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001273 salt_len = *p++; /* salt_len */
1274 p += salt_len; /* salt */
1275 hash_len = *p++; /* p now points to next hashed name */
1276
1277 if (!CHECK_LEN(header, p, plen, hash_len))
1278 return 0;
1279
1280 if (digest_len == base32_len && hash_len == base32_len)
1281 {
1282 int rc = memcmp(workspace2, digest, digest_len);
1283
1284 if (rc == 0)
1285 {
1286 /* We found an NSEC3 whose hashed name exactly matches the query, so
1287 we just need to check the type map. p points to the RR data for the record. */
1288
1289 int offset = (type & 0xff) >> 3;
1290 int mask = 0x80 >> (type & 0x07);
1291
1292 p += hash_len; /* skip next-domain hash */
1293 rdlen -= p - psave;
1294
1295 if (!CHECK_LEN(header, p, plen, rdlen))
1296 return 0;
1297
Simon Kelley9a31b682015-12-15 10:20:39 +00001298 if (rdlen >= 2 && p[0] == 0)
1299 {
Simon Kelleyec0628c2015-12-31 20:55:39 +00001300 /* If we can prove that there's no NS record, return that information. */
1301 if (nons && (p[2] & (0x80 >> T_NS)) != 0)
1302 *nons = 0;
1303
Simon Kelley9a31b682015-12-15 10:20:39 +00001304 /* A CNAME answer would also be valid, so if there's a CNAME is should
1305 have been returned. */
1306 if ((p[2] & (0x80 >> T_CNAME)) != 0)
1307 return 0;
1308
1309 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001310 DS from the wrong side of the delegation. For the root DS,
1311 this is expected. */
1312 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001313 return 0;
1314 }
1315
Simon Kelleyfbc52052014-12-23 15:46:08 +00001316 while (rdlen >= 2)
1317 {
1318 if (p[0] == type >> 8)
1319 {
1320 /* Does the NSEC3 say our type exists? */
1321 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001322 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001323
Josh Soref730c6742017-02-06 16:14:04 +00001324 break; /* finished checking */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001325 }
1326
1327 rdlen -= p[1];
1328 p += p[1];
1329 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001330
Simon Kelleyfbc52052014-12-23 15:46:08 +00001331 return 1;
1332 }
Simon Kelley4d25cf82015-06-06 23:13:57 +01001333 else if (rc < 0)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001334 {
1335 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1336 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001337 if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001338 {
1339 if ((flags & 0x01) && nons) /* opt out */
1340 *nons = 0;
1341
1342 return 1;
1343 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001344 }
1345 else
1346 {
1347 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001348 if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001349 {
1350 if ((flags & 0x01) && nons) /* opt out */
1351 *nons = 0;
1352
1353 return 1;
1354 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001355 }
1356 }
1357 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001358
Simon Kelleyfbc52052014-12-23 15:46:08 +00001359 return 0;
1360}
1361
Simon Kelley24187532014-02-24 21:46:44 +00001362static 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 +00001363 char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001364{
Simon Kelleya857daa2014-02-24 21:01:09 +00001365 unsigned char *salt, *p, *digest;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001366 int digest_len, i, iterations, salt_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001367 struct nettle_hash const *hash;
1368 char *closest_encloser, *next_closest, *wildcard;
Simon Kelley97e618a2015-01-07 21:55:43 +00001369
1370 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001371 *nons = 1;
Simon Kelley97e618a2015-01-07 21:55:43 +00001372
Simon Kelley5107ace2014-02-23 10:48:32 +00001373 /* Look though the NSEC3 records to find the first one with
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001374 an algorithm we support.
Simon Kelley5107ace2014-02-23 10:48:32 +00001375
1376 Take the algo, iterations, and salt of that record
1377 as the ones we're going to use, and prune any
1378 that don't match. */
1379
1380 for (i = 0; i < nsec_count; i++)
1381 {
1382 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001383 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001384
1385 p += 10; /* type, class, TTL, rdlen */
1386 algo = *p++;
1387
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001388 if ((hash = hash_find(nsec3_digest_name(algo))))
Simon Kelley5107ace2014-02-23 10:48:32 +00001389 break; /* known algo */
1390 }
1391
1392 /* No usable NSEC3s */
1393 if (i == nsec_count)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001394 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001395
1396 p++; /* flags */
Simon Kelley40205a02016-03-14 21:24:00 +00001397
Simon Kelley5107ace2014-02-23 10:48:32 +00001398 GETSHORT (iterations, p);
Simon Kelley40205a02016-03-14 21:24:00 +00001399 /* Upper-bound iterations, to avoid DoS.
1400 Strictly, there are lower bounds for small keys, but
1401 since we don't have key size info here, at least limit
1402 to the largest bound, for 4096-bit keys. RFC 5155 10.3 */
1403 if (iterations > 2500)
1404 return 0;
1405
Simon Kelley5107ace2014-02-23 10:48:32 +00001406 salt_len = *p++;
1407 salt = p;
1408 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001409 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001410
1411 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1412 for (i = 0; i < nsec_count; i++)
1413 {
1414 unsigned char *nsec3p = nsecs[i];
Simon Kelleyce5732e2015-12-20 21:39:19 +00001415 int this_iter, flags;
Simon Kelley5107ace2014-02-23 10:48:32 +00001416
1417 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1418
1419 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001420 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001421
1422 p += 10; /* type, class, TTL, rdlen */
1423
1424 if (*p++ != algo)
1425 continue;
1426
Simon Kelleyce5732e2015-12-20 21:39:19 +00001427 flags = *p++; /* flags */
Simon Kelley5107ace2014-02-23 10:48:32 +00001428
Simon Kelleyce5732e2015-12-20 21:39:19 +00001429 /* 5155 8.2 */
1430 if (flags != 0 && flags != 1)
1431 continue;
1432
Simon Kelleya857daa2014-02-24 21:01:09 +00001433 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001434 if (this_iter != iterations)
1435 continue;
1436
1437 if (salt_len != *p++)
1438 continue;
1439
1440 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001441 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001442
1443 if (memcmp(p, salt, salt_len) != 0)
1444 continue;
1445
1446 /* All match, put the pointer back */
1447 nsecs[i] = nsec3p;
1448 }
1449
Simon Kelleyfbc52052014-12-23 15:46:08 +00001450 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001451 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001452
Simon Kelleya969ba62018-01-20 23:08:38 +00001453 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 +00001454 return 1;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001455
1456 /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
1457 or an answer inferred from a wildcard record. */
Simon Kelley5107ace2014-02-23 10:48:32 +00001458 closest_encloser = name;
1459 next_closest = NULL;
1460
1461 do
1462 {
1463 if (*closest_encloser == '.')
1464 closest_encloser++;
1465
Simon Kelleyfbc52052014-12-23 15:46:08 +00001466 if (wildname && hostname_isequal(closest_encloser, wildname))
1467 break;
1468
Simon Kelleya857daa2014-02-24 21:01:09 +00001469 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001470 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001471
1472 for (i = 0; i < nsec_count; i++)
1473 if ((p = nsecs[i]))
1474 {
Simon Kelley394ff492015-03-29 22:17:14 +01001475 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001476 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001477 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001478
Simon Kelleya857daa2014-02-24 21:01:09 +00001479 if (digest_len == base32_len &&
1480 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001481 break; /* Gotit */
1482 }
1483
1484 if (i != nsec_count)
1485 break;
1486
1487 next_closest = closest_encloser;
1488 }
1489 while ((closest_encloser = strchr(closest_encloser, '.')));
1490
Simon Kelleya7b27e82016-03-16 19:11:52 +00001491 if (!closest_encloser || !next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001492 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001493
Simon Kelley24187532014-02-24 21:46:44 +00001494 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001495 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001496 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001497
Simon Kelleya969ba62018-01-20 23:08:38 +00001498 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001499 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001500
1501 /* Finally, check that there's no seat of wildcard synthesis */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001502 if (!wildname)
1503 {
1504 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001505 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001506
1507 wildcard--;
1508 *wildcard = '*';
1509
1510 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001511 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001512
Simon Kelleya969ba62018-01-20 23:08:38 +00001513 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001514 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001515 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001516
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001517 return 1;
1518}
1519
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001520static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons, int *nsec_ttl)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001521{
Simon Kelley4fe67442018-01-19 12:26:08 +00001522 static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
1523 static int nsecset_sz = 0, rrsig_labels_sz = 0;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001524
1525 int type_found = 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001526 unsigned char *auth_start, *p = skip_questions(header, plen);
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001527 int type, class, rdlen, i, nsecs_found;
1528 unsigned long ttl;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001529
1530 /* Move to NS section */
1531 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1532 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001533
1534 auth_start = p;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001535
Simon Kelleye24abf22019-09-03 22:48:39 +01001536 for (nsecs_found = 0, i = 0; i < ntohs(header->nscount); i++)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001537 {
1538 unsigned char *pstart = p;
1539
Simon Kelley4fe67442018-01-19 12:26:08 +00001540 if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001541 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001542
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001543 GETSHORT(type, p);
1544 GETSHORT(class, p);
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001545 GETLONG(ttl, p);
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001546 GETSHORT(rdlen, p);
1547
1548 if (class == qclass && (type == T_NSEC || type == T_NSEC3))
1549 {
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001550 if (nsec_ttl)
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001551 {
1552 /* Limit TTL with sig TTL */
1553 if (daemon->rr_status[ntohs(header->ancount) + i] < ttl)
1554 ttl = daemon->rr_status[ntohs(header->ancount) + i];
1555 *nsec_ttl = ttl;
1556 }
1557
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001558 /* No mixed NSECing 'round here, thankyouverymuch */
1559 if (type_found != 0 && type_found != type)
1560 return 0;
1561
1562 type_found = type;
1563
1564 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1565 return 0;
1566
Simon Kelley4fe67442018-01-19 12:26:08 +00001567 if (type == T_NSEC)
1568 {
1569 /* If we're looking for NSECs, find the corresponding SIGs, to
1570 extract the labels value, which we need in case the NSECs
1571 are the result of wildcard expansion.
1572 Note that the NSEC may not have been validated yet
1573 so if there are multiple SIGs, make sure the label value
1574 is the same in all, to avoid be duped by a rogue one.
1575 If there are no SIGs, that's an error */
1576 unsigned char *p1 = auth_start;
1577 int res, j, rdlen1, type1, class1;
1578
1579 if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
1580 return 0;
1581
1582 rrsig_labels[nsecs_found] = NULL;
1583
1584 for (j = ntohs(header->nscount); j != 0; j--)
1585 {
1586 if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
1587 return 0;
1588
1589 GETSHORT(type1, p1);
1590 GETSHORT(class1, p1);
1591 p1 += 4; /* TTL */
1592 GETSHORT(rdlen1, p1);
1593
1594 if (!CHECK_LEN(header, p1, plen, rdlen1))
1595 return 0;
1596
1597 if (res == 1 && class1 == qclass && type1 == T_RRSIG)
1598 {
1599 int type_covered;
1600 unsigned char *psav = p1;
1601
Simon Kelleycd7df612018-01-20 00:10:55 +00001602 if (rdlen1 < 18)
Simon Kelley4fe67442018-01-19 12:26:08 +00001603 return 0; /* bad packet */
1604
1605 GETSHORT(type_covered, p1);
1606
1607 if (type_covered == T_NSEC)
1608 {
1609 p1++; /* algo */
1610
1611 /* labels field must be the same in every SIG we find. */
1612 if (!rrsig_labels[nsecs_found])
1613 rrsig_labels[nsecs_found] = p1;
1614 else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
1615 return 0;
1616 }
1617 p1 = psav;
1618 }
1619
1620 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1621 return 0;
1622 }
1623
1624 /* Must have found at least one sig. */
1625 if (!rrsig_labels[nsecs_found])
1626 return 0;
1627 }
1628
1629 nsecset[nsecs_found++] = pstart;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001630 }
1631
1632 if (!ADD_RDLEN(header, p, plen, rdlen))
1633 return 0;
1634 }
1635
1636 if (type_found == T_NSEC)
Simon Kelley4fe67442018-01-19 12:26:08 +00001637 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 +00001638 else if (type_found == T_NSEC3)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001639 return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001640 else
1641 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001642}
Simon Kelley9a31b682015-12-15 10:20:39 +00001643
1644/* Check signing status of name.
1645 returns:
Simon Kelley3b799c82015-12-17 16:58:04 +00001646 STAT_SECURE zone is signed.
1647 STAT_INSECURE zone proved unsigned.
1648 STAT_NEED_DS require DS record of name returned in keyname.
1649 STAT_NEED_KEY require DNSKEY record of name returned in keyname.
Simon Kelley9a31b682015-12-15 10:20:39 +00001650 name returned unaltered.
1651*/
1652static int zone_status(char *name, int class, char *keyname, time_t now)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001653{
Simon Kelleya63b8b82016-01-12 11:28:58 +00001654 int name_start = strlen(name); /* for when TA is root */
Simon Kelley9a31b682015-12-15 10:20:39 +00001655 struct crec *crecp;
1656 char *p;
Simon Kelleya63b8b82016-01-12 11:28:58 +00001657
1658 /* First, work towards the root, looking for a trust anchor.
1659 This can either be one configured, or one previously cached.
1660 We can assume, if we don't find one first, that there is
1661 a trust anchor at the root. */
1662 for (p = name; p; p = strchr(p, '.'))
1663 {
1664 if (*p == '.')
1665 p++;
1666
1667 if (cache_find_by_name(NULL, p, now, F_DS))
1668 {
1669 name_start = p - name;
1670 break;
1671 }
1672 }
Simon Kelley367341f2016-01-12 15:58:23 +00001673
Simon Kelleya63b8b82016-01-12 11:28:58 +00001674 /* Now work away from the trust anchor */
Simon Kelley9a31b682015-12-15 10:20:39 +00001675 while (1)
1676 {
1677 strcpy(keyname, &name[name_start]);
1678
1679 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
1680 return STAT_NEED_DS;
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001681
Josh Soref730c6742017-02-06 16:14:04 +00001682 /* F_DNSSECOK misused in DS cache records to non-existence of NS record.
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001683 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
1684 but that's because there's no NS record either, ie this isn't the start
1685 of a zone. We only prove that the DNS tree below a node is unsigned when
1686 we prove that we're at a zone cut AND there's no DS record. */
1687 if (crecp->flags & F_NEG)
1688 {
1689 if (crecp->flags & F_DNSSECOK)
1690 return STAT_INSECURE; /* proved no DS here */
1691 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001692 else
Simon Kelley2dbba342015-12-16 13:41:58 +00001693 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001694 /* If all the DS records have digest and/or sig algos we don't support,
1695 then the zone is insecure. Note that if an algo
1696 appears in the DS, then RRSIGs for that algo MUST
1697 exist for each RRset: 4035 para 2.2 So if we find
1698 a DS here with digest and sig we can do, we're entitled
1699 to assume we can validate the zone and if we can't later,
1700 because an RRSIG is missing we return BOGUS.
1701 */
Simon Kelley2dbba342015-12-16 13:41:58 +00001702 do
1703 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001704 if (crecp->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001705 ds_digest_name(crecp->addr.ds.digest) &&
1706 algo_digest_name(crecp->addr.ds.algo))
Simon Kelleya86fdf42015-12-20 21:19:20 +00001707 break;
Simon Kelley2dbba342015-12-16 13:41:58 +00001708 }
1709 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
Simon Kelley2dbba342015-12-16 13:41:58 +00001710
Simon Kelleya86fdf42015-12-20 21:19:20 +00001711 if (!crecp)
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001712 return STAT_INSECURE;
Simon Kelley2dbba342015-12-16 13:41:58 +00001713 }
1714
Simon Kelley9a31b682015-12-15 10:20:39 +00001715 if (name_start == 0)
1716 break;
1717
1718 for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
1719
1720 if (p != name)
1721 p++;
1722
1723 name_start = p - name;
1724 }
1725
1726 return STAT_SECURE;
1727}
1728
1729/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3)
1730 Return code:
1731 STAT_SECURE if it validates.
1732 STAT_INSECURE at least one RRset not validated, because in unsigned zone.
1733 STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
1734 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
Simon Kelleya6004d72017-10-25 17:48:19 +01001735 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
1736
Simon Kelley373e9172017-12-01 22:40:56 +00001737 daemon->rr_status points to a char array which corressponds to the RRs in the
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001738 answer and auth sections. This is set to 1 for each RR which is validated, and 0 for any which aren't.
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001739
1740 When validating replies to DS records, we're only interested in the NSEC{3} RRs in the auth section.
1741 Other RRs in that section missing sigs will not cause am INSECURE reply. We determine this mode
1742 is the nons argument is non-NULL.
Simon Kelley9a31b682015-12-15 10:20:39 +00001743*/
1744int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001745 int *class, int check_unsigned, int *neganswer, int *nons, int *nsec_ttl)
Simon Kelley9a31b682015-12-15 10:20:39 +00001746{
1747 static unsigned char **targets = NULL;
1748 static int target_sz = 0;
1749
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001750 unsigned char *ans_start, *p1, *p2;
Simon Kelleya6004d72017-10-25 17:48:19 +01001751 int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
Simon Kelley91421cb2018-10-18 19:21:55 +01001752 int i, j, rc = STAT_INSECURE;
Simon Kelleya6004d72017-10-25 17:48:19 +01001753 int secure = STAT_SECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001754
Simon Kelley373e9172017-12-01 22:40:56 +00001755 /* extend rr_status if necessary */
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001756 if (daemon->rr_status_sz < ntohs(header->ancount) + ntohs(header->nscount))
Simon Kelley373e9172017-12-01 22:40:56 +00001757 {
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001758 unsigned long *new = whine_malloc(sizeof(*daemon->rr_status) * (ntohs(header->ancount) + ntohs(header->nscount) + 64));
Simon Kelley373e9172017-12-01 22:40:56 +00001759
1760 if (!new)
1761 return STAT_BOGUS;
1762
1763 free(daemon->rr_status);
1764 daemon->rr_status = new;
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001765 daemon->rr_status_sz = ntohs(header->ancount) + ntohs(header->nscount) + 64;
Simon Kelley373e9172017-12-01 22:40:56 +00001766 }
1767
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001768 memset(daemon->rr_status, 0, sizeof(*daemon->rr_status) * daemon->rr_status_sz);
Simon Kelleya6004d72017-10-25 17:48:19 +01001769
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001770 if (neganswer)
1771 *neganswer = 0;
1772
Simon Kelley87070192014-03-01 20:48:24 +00001773 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001774 return STAT_BOGUS;
1775
Simon Kelley87070192014-03-01 20:48:24 +00001776 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001777 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001778
Simon Kelley9a31b682015-12-15 10:20:39 +00001779 p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001780
Simon Kelley9a31b682015-12-15 10:20:39 +00001781 /* Find all the targets we're looking for answers to.
1782 The zeroth array element is for the query, subsequent ones
1783 for CNAME targets, unless the query is for a CNAME. */
1784
1785 if (!expand_workspace(&targets, &target_sz, 0))
1786 return STAT_BOGUS;
1787
1788 targets[0] = p1;
1789 targetidx = 1;
1790
Simon Kelley394ff492015-03-29 22:17:14 +01001791 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001792 return STAT_BOGUS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001793
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001794 GETSHORT(qtype, p1);
1795 GETSHORT(qclass, p1);
1796 ans_start = p1;
1797
Simon Kelley9a31b682015-12-15 10:20:39 +00001798 /* Can't validate an RRSIG query */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001799 if (qtype == T_RRSIG)
1800 return STAT_INSECURE;
Simon Kelleye3ec6f02015-06-12 21:39:11 +01001801
Simon Kelley9a31b682015-12-15 10:20:39 +00001802 if (qtype != T_CNAME)
1803 for (j = ntohs(header->ancount); j != 0; j--)
1804 {
1805 if (!(p1 = skip_name(p1, header, plen, 10)))
1806 return STAT_BOGUS; /* bad packet */
1807
1808 GETSHORT(type2, p1);
1809 p1 += 6; /* class, TTL */
1810 GETSHORT(rdlen2, p1);
1811
1812 if (type2 == T_CNAME)
1813 {
1814 if (!expand_workspace(&targets, &target_sz, targetidx))
1815 return STAT_BOGUS;
1816
1817 targets[targetidx++] = p1; /* pointer to target name */
1818 }
1819
1820 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1821 return STAT_BOGUS;
1822 }
1823
Simon Kelley0fc2f312014-01-08 10:26:58 +00001824 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001825 {
Simon Kelley91421cb2018-10-18 19:21:55 +01001826 if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
1827 return STAT_BOGUS;
1828
1829 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001830 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001831
1832 GETSHORT(type1, p1);
1833 GETSHORT(class1, p1);
1834 p1 += 4; /* TTL */
1835 GETSHORT(rdlen1, p1);
1836
1837 /* Don't try and validate RRSIGs! */
Simon Kelleya6004d72017-10-25 17:48:19 +01001838 if (type1 == T_RRSIG)
1839 continue;
1840
1841 /* Check if we've done this RRset already */
1842 for (p2 = ans_start, j = 0; j < i; j++)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001843 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001844 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1845 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001846
Simon Kelleya6004d72017-10-25 17:48:19 +01001847 GETSHORT(type2, p2);
1848 GETSHORT(class2, p2);
1849 p2 += 4; /* TTL */
1850 GETSHORT(rdlen2, p2);
1851
1852 if (type2 == type1 && class2 == class1 && rc == 1)
1853 break; /* Done it before: name, type, class all match. */
1854
1855 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1856 return STAT_BOGUS;
1857 }
1858
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001859 /* Done already: copy the validation status */
Simon Kelleya6004d72017-10-25 17:48:19 +01001860 if (j != i)
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001861 daemon->rr_status[i] = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +01001862 else
1863 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001864 /* Not done, validate now */
Simon Kelleya6004d72017-10-25 17:48:19 +01001865 int sigcnt, rrcnt;
1866 char *wildname;
1867
1868 if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
1869 return STAT_BOGUS;
1870
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001871 /* 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 +01001872 if (sigcnt == 0)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001873 {
Simon Kelley69a04772019-09-03 16:49:02 +01001874 /* NSEC and NSEC3 records must be signed. We make this assumption elsewhere. */
1875 if (type1 == T_NSEC || type1 == T_NSEC3)
1876 rc = STAT_INSECURE;
1877 else if (nons && i >= ntohs(header->ancount))
1878 /* If we're validating a DS reply, rather than looking for the value of AD bit,
1879 we only care that NSEC and NSEC3 RRs in the auth section are signed.
1880 Return SECURE even if others (SOA....) are not. */
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001881 rc = STAT_SECURE;
1882 else
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001883 {
Simon Kelley69a04772019-09-03 16:49:02 +01001884 /* unsigned RRsets in auth section are not BOGUS, but do make reply insecure. */
1885 if (check_unsigned && i < ntohs(header->ancount))
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001886 {
1887 rc = zone_status(name, class1, keyname, now);
1888 if (rc == STAT_SECURE)
1889 rc = STAT_BOGUS;
1890 if (class)
1891 *class = class1; /* Class for NEED_DS or NEED_KEY */
1892 }
1893 else
1894 rc = STAT_INSECURE;
1895
1896 if (rc != STAT_INSECURE)
1897 return rc;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001898 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001899 }
1900 else
1901 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001902 /* explore_rrset() gives us key name from sigs in keyname.
1903 Can't overwrite name here. */
1904 strcpy(daemon->workspacename, keyname);
1905 rc = zone_status(daemon->workspacename, class1, keyname, now);
Simon Kelleya6004d72017-10-25 17:48:19 +01001906
1907 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001908 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001909 if (class)
Simon Kelley3b799c82015-12-17 16:58:04 +00001910 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley9a31b682015-12-15 10:20:39 +00001911 return rc;
Simon Kelleya6004d72017-10-25 17:48:19 +01001912 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001913
Simon Kelleya6004d72017-10-25 17:48:19 +01001914 /* Zone is insecure, don't need to validate RRset */
1915 if (rc == STAT_SECURE)
Simon Kelley9a31b682015-12-15 10:20:39 +00001916 {
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001917 unsigned long sig_ttl;
Simon Kelleya6004d72017-10-25 17:48:19 +01001918 rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001919 rrcnt, name, keyname, &wildname, NULL, 0, 0, 0, &sig_ttl);
Simon Kelleya6004d72017-10-25 17:48:19 +01001920
1921 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
1922 {
1923 if (class)
1924 *class = class1; /* Class for DS or DNSKEY */
1925 return rc;
1926 }
1927
Simon Kelley9a31b682015-12-15 10:20:39 +00001928 /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
Simon Kelleya6004d72017-10-25 17:48:19 +01001929
1930 /* Note that RR is validated */
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001931 daemon->rr_status[i] = sig_ttl;
Simon Kelleya6004d72017-10-25 17:48:19 +01001932
Simon Kelley9a31b682015-12-15 10:20:39 +00001933 /* Note if we've validated either the answer to the question
1934 or the target of a CNAME. Any not noted will need NSEC or
1935 to be in unsigned space. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001936 for (j = 0; j <targetidx; j++)
1937 if ((p2 = targets[j]))
1938 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001939 int rc1;
1940 if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001941 return STAT_BOGUS; /* bad packet */
1942
Simon Kelleya6004d72017-10-25 17:48:19 +01001943 if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
Simon Kelley9a31b682015-12-15 10:20:39 +00001944 targets[j] = NULL;
1945 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001946
1947 /* An attacker replay a wildcard answer with a different
1948 answer and overlay a genuine RR. To prove this
1949 hasn't happened, the answer must prove that
1950 the genuine record doesn't exist. Check that here.
1951 Note that we may not yet have validated the NSEC/NSEC3 RRsets.
1952 That's not a problem since if the RRsets later fail
1953 we'll return BOGUS then. */
1954 if (rc == STAT_SECURE_WILDCARD &&
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001955 !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL, NULL))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001956 return STAT_BOGUS;
Simon Kelleya6004d72017-10-25 17:48:19 +01001957
1958 rc = STAT_SECURE;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001959 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001960 }
1961 }
1962
Simon Kelleya6004d72017-10-25 17:48:19 +01001963 if (rc == STAT_INSECURE)
1964 secure = STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001965 }
1966
Simon Kelley9a31b682015-12-15 10:20:39 +00001967 /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
Simon Kelley7f008432018-04-15 20:01:49 +01001968 if (secure == STAT_SECURE)
Simon Kelley4e72fec2018-04-11 22:49:31 +01001969 for (j = 0; j <targetidx; j++)
1970 if ((p2 = targets[j]))
1971 {
1972 if (neganswer)
1973 *neganswer = 1;
1974
1975 if (!extract_name(header, plen, &p2, name, 1, 10))
1976 return STAT_BOGUS; /* bad packet */
1977
1978 /* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
1979
1980 /* For anything other than a DS record, this situation is OK if either
1981 the answer is in an unsigned zone, or there's a NSEC records. */
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001982 if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons, nsec_ttl))
Simon Kelley4e72fec2018-04-11 22:49:31 +01001983 {
1984 /* Empty DS without NSECS */
1985 if (qtype == T_DS)
1986 return STAT_BOGUS;
1987
1988 if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
1989 {
1990 if (class)
1991 *class = qclass; /* Class for NEED_DS or NEED_KEY */
1992 return rc;
1993 }
1994
1995 return STAT_BOGUS; /* signed zone, no NSECs */
1996 }
1997 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001998
Simon Kelleya6004d72017-10-25 17:48:19 +01001999 return secure;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002000}
2001
2002
Giovanni Bajo3471f182012-04-25 17:49:16 +02002003/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002004int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02002005{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002006 if (alg == 1)
2007 {
2008 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
2009 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002010 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002011 }
2012 else
2013 {
Simon Kelley1633e302014-02-10 16:42:46 +00002014 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002015 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002016
Simon Kelley0fc2f312014-01-08 10:26:58 +00002017 for (i = 0; i < keylen; ++i)
2018 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002019
Simon Kelley0fc2f312014-01-08 10:26:58 +00002020 ac += (ac >> 16) & 0xffff;
2021 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002022 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002023}
2024
Simon Kelley33702ab2015-12-28 23:17:15 +00002025size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
Simon Kelleye1791f32018-10-06 23:23:23 +01002026 int type, int edns_pktsz)
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002027{
2028 unsigned char *p;
Simon Kelleya77cec82015-05-08 16:25:38 +01002029 size_t ret;
Giovanni Bajo0304d282012-05-02 03:29:52 +02002030
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002031 header->qdcount = htons(1);
2032 header->ancount = htons(0);
2033 header->nscount = htons(0);
2034 header->arcount = htons(0);
2035
2036 header->hb3 = HB3_RD;
2037 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002038 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2039 this allows it to select auth servers when one is returning bad data. */
2040 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002041
2042 /* ID filled in later */
2043
2044 p = (unsigned char *)(header+1);
2045
Simon Kelley0549c732017-09-25 18:17:11 +01002046 p = do_rfc1035_name(p, name, NULL);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002047 *p++ = 0;
2048 PUTSHORT(type, p);
2049 PUTSHORT(class, p);
2050
Simon Kelleya77cec82015-05-08 16:25:38 +01002051 ret = add_do_bit(header, p - (unsigned char *)header, end);
2052
Simon Kelley5bb88f02015-12-21 16:23:47 +00002053 if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
Simon Kelleya77cec82015-05-08 16:25:38 +01002054 PUTSHORT(edns_pktsz, p);
2055
2056 return ret;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002057}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002058
2059unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2060{
2061 int q;
2062 unsigned int len;
2063 unsigned char *p = (unsigned char *)(header+1);
2064 const struct nettle_hash *hash;
2065 void *ctx;
2066 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002067
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002068 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2069 return NULL;
2070
2071 for (q = ntohs(header->qdcount); q != 0; q--)
2072 {
Simon Kelley394ff492015-03-29 22:17:14 +01002073 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002074 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002075
2076 len = to_wire(name);
2077 hash->update(ctx, len, (unsigned char *)name);
2078 /* CRC the class and type as well */
2079 hash->update(ctx, 4, p);
2080
2081 p += 4;
2082 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002083 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002084 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002085
2086 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002087 return digest;
2088}
2089
Simon Kelley0fc2f312014-01-08 10:26:58 +00002090#endif /* HAVE_DNSSEC */