blob: 3ee1e9eb7eee40310d10c091498ef75c46a01d71 [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 Kelley4e96a4b2020-11-11 23:25:04 +0000226/* Return bytes of canonicalised rrdata one by one.
227 Init state->ip with the RR, and state->end with the end of same.
228 Init state->op to NULL.
229 Init state->desc to RR descriptor.
230 Init state->buff with a MAXDNAME * 2 buffer.
231
232 After each call which returns 1, state->op points to the next byte of data.
233 On returning 0, the end has been reached.
234*/
235struct rdata_state {
236 u16 *desc;
237 size_t c;
238 unsigned char *end, *ip, *op;
239 char *buff;
240};
241
242static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state *state)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000243{
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000244 int d;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000245
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000246 if (state->op && state->c != 1)
Simon Kelley094b5c32014-12-21 16:11:52 +0000247 {
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000248 state->op++;
249 state->c--;
250 return 1;
Simon Kelley094b5c32014-12-21 16:11:52 +0000251 }
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000252
253 while (1)
254 {
255 d = *(state->desc);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000256
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000257 if (d == (u16)-1)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000258 {
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000259 /* all the bytes to the end. */
260 if ((state->c = state->end - state->ip) != 0)
261 {
262 state->op = state->ip;
263 state->ip = state->end;;
264 }
265 else
266 return 0;
267 }
268 else
269 {
270 state->desc++;
271
272 if (d == (u16)0)
273 {
274 /* domain-name, canonicalise */
275 int len;
276
277 if (!extract_name(header, plen, &state->ip, state->buff, 1, 0) ||
278 (len = to_wire(state->buff)) == 0)
279 continue;
280
281 state->c = len;
282 state->op = (unsigned char *)state->buff;
283 }
284 else
285 {
286 /* plain data preceding a domain-name, don't run off the end of the data */
287 if ((state->end - state->ip) < d)
288 d = state->end - state->ip;
289
290 if (d == 0)
291 continue;
292
293 state->op = state->ip;
294 state->c = d;
295 state->ip += d;
296 }
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000297 }
298
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000299 return 1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000300 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000301}
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000302
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000303/* Bubble sort the RRset into the canonical order. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000304
Simon Kelleye5412452018-01-06 22:16:31 +0000305static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
306 unsigned char **rrset, char *buff1, char *buff2)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000307{
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000308 int swap, i, j;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000309
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000310 do
311 {
312 for (swap = 0, i = 0; i < rrsetidx-1; i++)
313 {
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000314 int rdlen1, rdlen2;
315 struct rdata_state state1, state2;
316
Simon Kelley5107ace2014-02-23 10:48:32 +0000317 /* Note that these have been determined to be OK previously,
318 so we don't need to check for NULL return here. */
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000319 state1.ip = skip_name(rrset[i], header, plen, 10);
320 state2.ip = skip_name(rrset[i+1], header, plen, 10);
321 state1.op = state2.op = NULL;
322 state1.buff = buff1;
323 state2.buff = buff2;
324 state1.desc = state2.desc = rr_desc;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000325
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000326 state1.ip += 8; /* skip class, type, ttl */
327 GETSHORT(rdlen1, state1.ip);
328 if (!CHECK_LEN(header, state1.ip, plen, rdlen1))
329 return rrsetidx; /* short packet */
330 state1.end = state1.ip + rdlen1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000331
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000332 state2.ip += 8; /* skip class, type, ttl */
333 GETSHORT(rdlen2, state2.ip);
334 if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
335 return rrsetidx; /* short packet */
336 state2.end = state2.ip + rdlen2;
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000337
Simon Kelley8ebdc362021-01-22 18:50:43 +0000338 /* If the RR has no names in it then canonicalisation
339 is the identity function and we can compare
340 the RRs directly. If not we compare the
341 canonicalised RRs one byte at a time. */
342 if (*rr_desc == (u16)-1)
343 {
344 int rdmin = rdlen1 > rdlen2 ? rdlen2 : rdlen1;
345 int cmp = memcmp(state1.ip, state2.ip, rdmin);
346
347 if (cmp > 0 || (cmp == 0 && rdlen1 > rdmin))
348 {
349 unsigned char *tmp = rrset[i+1];
350 rrset[i+1] = rrset[i];
351 rrset[i] = tmp;
352 swap = 1;
353 }
354 else if (cmp == 0 && (rdlen1 == rdlen2))
Simon Kelleye5412452018-01-06 22:16:31 +0000355 {
356 /* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
357 for (j = i+1; j < rrsetidx-1; j++)
358 rrset[j] = rrset[j+1];
359 rrsetidx--;
360 i--;
361 }
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000362 }
Simon Kelley8ebdc362021-01-22 18:50:43 +0000363 else
364 /* Comparing canonicalised RRs, byte-at-a-time. */
365 while (1)
366 {
367 int ok1, ok2;
368
369 ok1 = get_rdata(header, plen, &state1);
370 ok2 = get_rdata(header, plen, &state2);
371
372 if (!ok1 && !ok2)
373 {
374 /* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
375 for (j = i+1; j < rrsetidx-1; j++)
376 rrset[j] = rrset[j+1];
377 rrsetidx--;
378 i--;
379 break;
380 }
381 else if (ok1 && (!ok2 || *state1.op > *state2.op))
382 {
383 unsigned char *tmp = rrset[i+1];
384 rrset[i+1] = rrset[i];
385 rrset[i] = tmp;
386 swap = 1;
387 break;
388 }
389 else if (ok2 && (!ok1 || *state2.op > *state1.op))
390 break;
391
392 /* arrive here when bytes are equal, go round the loop again
393 and compare the next ones. */
394 }
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000395 }
396 } while (swap);
Simon Kelleye5412452018-01-06 22:16:31 +0000397
398 return rrsetidx;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000399}
400
Simon Kelley9a31b682015-12-15 10:20:39 +0000401static unsigned char **rrset = NULL, **sigs = NULL;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000402
Josh Soref730c6742017-02-06 16:14:04 +0000403/* Get pointers to RRset members and signature(s) for same.
Simon Kelley9a31b682015-12-15 10:20:39 +0000404 Check signatures, and return keyname associated in keyname. */
405static int explore_rrset(struct dns_header *header, size_t plen, int class, int type,
406 char *name, char *keyname, int *sigcnt, int *rrcnt)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000407{
Simon Kelley9a31b682015-12-15 10:20:39 +0000408 static int rrset_sz = 0, sig_sz = 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000409 unsigned char *p;
Simon Kelley9a31b682015-12-15 10:20:39 +0000410 int rrsetidx, sigidx, j, rdlen, res;
Simon Kelley9a31b682015-12-15 10:20:39 +0000411 int gotkey = 0;
412
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000413 if (!(p = skip_questions(header, plen)))
Simon Kelley05299fd2019-07-15 22:04:20 +0100414 return 0;
Simon Kelley5ada8882014-01-09 22:25:03 +0000415
Simon Kelley9a31b682015-12-15 10:20:39 +0000416 /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000417 for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
418 j != 0; j--)
419 {
420 unsigned char *pstart, *pdata;
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000421 int stype, sclass, type_covered;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000422
423 pstart = p;
424
425 if (!(res = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley05299fd2019-07-15 22:04:20 +0100426 return 0; /* bad packet */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000427
428 GETSHORT(stype, p);
429 GETSHORT(sclass, p);
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100430
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000431 pdata = p;
432
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100433 p += 4; /* TTL */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000434 GETSHORT(rdlen, p);
435
Simon Kelleye7829ae2014-01-22 22:21:51 +0000436 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley9a31b682015-12-15 10:20:39 +0000437 return 0;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000438
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000439 if (res == 1 && sclass == class)
440 {
441 if (stype == type)
442 {
Simon Kelley613ad152014-02-25 23:02:28 +0000443 if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
Simon Kelley9a31b682015-12-15 10:20:39 +0000444 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +0000445
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000446 rrset[rrsetidx++] = pstart;
447 }
448
449 if (stype == T_RRSIG)
450 {
Simon Kelley613ad152014-02-25 23:02:28 +0000451 if (rdlen < 18)
Simon Kelley9a31b682015-12-15 10:20:39 +0000452 return 0; /* bad packet */
Simon Kelley613ad152014-02-25 23:02:28 +0000453
454 GETSHORT(type_covered, p);
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000455 p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
Simon Kelley613ad152014-02-25 23:02:28 +0000456
Simon Kelley9a31b682015-12-15 10:20:39 +0000457 if (gotkey)
458 {
459 /* If there's more than one SIG, ensure they all have same keyname */
460 if (extract_name(header, plen, &p, keyname, 0, 0) != 1)
461 return 0;
462 }
463 else
464 {
465 gotkey = 1;
466
467 if (!extract_name(header, plen, &p, keyname, 1, 0))
468 return 0;
469
470 /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
471 the name of the zone containing the RRset. We can't tell that
472 for certain, but we can check that the RRset name is equal to
473 or encloses the signers name, which should be enough to stop
474 an attacker using signatures made with the key of an unrelated
475 zone he controls. Note that the root key is always allowed. */
476 if (*keyname != 0)
477 {
478 char *name_start;
479 for (name_start = name; !hostname_isequal(name_start, keyname); )
480 if ((name_start = strchr(name_start, '.')))
481 name_start++; /* chop a label off and try again */
482 else
483 return 0;
484 }
485 }
486
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000487
488 if (type_covered == type)
Simon Kelley613ad152014-02-25 23:02:28 +0000489 {
490 if (!expand_workspace(&sigs, &sig_sz, sigidx))
Simon Kelley9a31b682015-12-15 10:20:39 +0000491 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +0000492
493 sigs[sigidx++] = pdata;
494 }
495
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100496 p = pdata + 6; /* restore for ADD_RDLEN */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000497 }
498 }
Simon Kelley613ad152014-02-25 23:02:28 +0000499
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000500 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley9a31b682015-12-15 10:20:39 +0000501 return 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000502 }
503
Simon Kelley9a31b682015-12-15 10:20:39 +0000504 *sigcnt = sigidx;
505 *rrcnt = rrsetidx;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000506
Simon Kelley9a31b682015-12-15 10:20:39 +0000507 return 1;
508}
509
510/* Validate a single RRset (class, type, name) in the supplied DNS reply
511 Return code:
512 STAT_SECURE if it validates.
513 STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
514 (In this case *wildcard_out points to the "body" of the wildcard within name.)
515 STAT_BOGUS signature is wrong, bad packet.
516 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
517 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
518
Simon Kelley2dbba342015-12-16 13:41:58 +0000519 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 +0000520 otherwise find the key in the cache.
521
Simon Kelley2dbba342015-12-16 13:41:58 +0000522 Name is unchanged on exit. keyname is used as workspace and trashed.
Simon Kelley9a31b682015-12-15 10:20:39 +0000523
524 Call explore_rrset first to find and count RRs and sigs.
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100525
526 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 +0000527*/
528static 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 +0100529 char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen,
530 int algo_in, int keytag_in, unsigned long *ttl_out)
Simon Kelley9a31b682015-12-15 10:20:39 +0000531{
532 unsigned char *p;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100533 int rdlen, j, name_labels, algo, labels, key_tag;
Simon Kelley9a31b682015-12-15 10:20:39 +0000534 struct crec *crecp = NULL;
Simon Kelleyc2bcd1e2015-12-15 17:25:21 +0000535 u16 *rr_desc = rrfilter_desc(type);
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100536 u32 sig_expiration, sig_inception;
537
538 unsigned long curtime = time(0);
539 int time_check = is_check_date(curtime);
540
Simon Kelley9a31b682015-12-15 10:20:39 +0000541 if (wildcard_out)
542 *wildcard_out = NULL;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000543
Simon Kelley9a31b682015-12-15 10:20:39 +0000544 name_labels = count_labels(name); /* For 4035 5.3.2 check */
545
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000546 /* Sort RRset records into canonical order.
Simon Kelleyd3873802014-02-23 16:20:46 +0000547 Note that at this point keyname and daemon->workspacename buffs are
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000548 unused, and used as workspace by the sort. */
Simon Kelleye5412452018-01-06 22:16:31 +0000549 rrsetidx = sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000550
551 /* Now try all the sigs to try and find one which validates */
552 for (j = 0; j <sigidx; j++)
553 {
Simon Kelleyd3873802014-02-23 16:20:46 +0000554 unsigned char *psav, *sig, *digest;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000555 int i, wire_len, sig_len;
556 const struct nettle_hash *hash;
557 void *ctx;
Simon Kelleyd3873802014-02-23 16:20:46 +0000558 char *name_start;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100559 u32 nsigttl, ttl, orig_ttl;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000560
561 p = sigs[j];
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100562 GETLONG(ttl, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000563 GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000564 psav = p;
565
Simon Kelley5ada8882014-01-09 22:25:03 +0000566 p += 2; /* type_covered - already checked */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000567 algo = *p++;
568 labels = *p++;
569 GETLONG(orig_ttl, p);
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000570 GETLONG(sig_expiration, p);
571 GETLONG(sig_inception, p);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000572 GETSHORT(key_tag, p);
573
Simon Kelley394ff492015-03-29 22:17:14 +0100574 if (!extract_name(header, plen, &p, keyname, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +0000575 return STAT_BOGUS;
Simon Kelleyd3873802014-02-23 16:20:46 +0000576
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100577 if ((time_check && !check_date_range(curtime, sig_inception, sig_expiration)) ||
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000578 labels > name_labels ||
579 !(hash = hash_find(algo_digest_name(algo))) ||
Simon Kelleye7829ae2014-01-22 22:21:51 +0000580 !hash_init(hash, &ctx, &digest))
581 continue;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100582
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000583 /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
584 if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
585 return STAT_NEED_KEY;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100586
587 if (ttl_out)
588 {
589 /* 4035 5.3.3 rules on TTLs */
590 if (orig_ttl < ttl)
591 ttl = orig_ttl;
592
593 if (time_check && difftime(sig_expiration, curtime) < ttl)
594 ttl = difftime(sig_expiration, curtime);
595
596 *ttl_out = ttl;
597 }
598
Simon Kelley86bec2d2014-01-13 21:31:20 +0000599 sig = p;
600 sig_len = rdlen - (p - psav);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000601
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000602 nsigttl = htonl(orig_ttl);
603
Simon Kelley86bec2d2014-01-13 21:31:20 +0000604 hash->update(ctx, 18, psav);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000605 wire_len = to_wire(keyname);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000606 hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000607 from_wire(keyname);
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000608
Simon Kelley059aded2020-11-12 23:09:15 +0000609#define RRBUFLEN 128 /* Most RRs are smaller than this. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000610
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000611 for (i = 0; i < rrsetidx; ++i)
612 {
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000613 int j;
614 struct rdata_state state;
615 u16 len;
616 unsigned char rrbuf[RRBUFLEN];
Simon Kelleyd3873802014-02-23 16:20:46 +0000617
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000618 p = rrset[i];
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000619
Simon Kelley394ff492015-03-29 22:17:14 +0100620 if (!extract_name(header, plen, &p, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +0000621 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000622
Simon Kelleyd3873802014-02-23 16:20:46 +0000623 name_start = name;
624
Simon Kelley5ada8882014-01-09 22:25:03 +0000625 /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
626 if (labels < name_labels)
627 {
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000628 for (j = name_labels - labels; j != 0; j--)
Simon Kelleyfbc52052014-12-23 15:46:08 +0000629 {
630 while (*name_start != '.' && *name_start != 0)
631 name_start++;
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000632 if (j != 1 && *name_start == '.')
Simon Kelleyfbc52052014-12-23 15:46:08 +0000633 name_start++;
634 }
635
636 if (wildcard_out)
637 *wildcard_out = name_start+1;
638
Simon Kelley5ada8882014-01-09 22:25:03 +0000639 name_start--;
640 *name_start = '*';
641 }
642
643 wire_len = to_wire(name_start);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000644 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
645 hash->update(ctx, 4, p); /* class and type */
646 hash->update(ctx, 4, (unsigned char *)&nsigttl);
Simon Kelley059aded2020-11-12 23:09:15 +0000647
648 p += 8; /* skip type, class, ttl */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000649 GETSHORT(rdlen, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000650 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000651 return STAT_BOGUS;
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000652
Simon Kelley059aded2020-11-12 23:09:15 +0000653 /* Optimisation for RR types which need no cannonicalisation.
654 This includes DNSKEY DS NSEC and NSEC3, which are also long, so
655 it saves lots of calls to get_rdata, and avoids the pessimal
656 segmented insertion, even with a small rrbuf[].
657
658 If canonicalisation is not needed, a simple insertion into the hash works.
659 */
660 if (*rr_desc == (u16)-1)
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000661 {
Simon Kelley059aded2020-11-12 23:09:15 +0000662 len = htons(rdlen);
663 hash->update(ctx, 2, (unsigned char *)&len);
664 hash->update(ctx, rdlen, p);
665 }
666 else
667 {
668 /* canonicalise rdata and calculate length of same, use
669 name buffer as workspace for get_rdata. */
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000670 state.ip = p;
671 state.op = NULL;
672 state.desc = rr_desc;
Simon Kelley059aded2020-11-12 23:09:15 +0000673 state.buff = name;
674 state.end = p + rdlen;
675
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000676 for (j = 0; get_rdata(header, plen, &state); j++)
Simon Kelley059aded2020-11-12 23:09:15 +0000677 if (j < RRBUFLEN)
678 rrbuf[j] = *state.op;
679
680 len = htons((u16)j);
681 hash->update(ctx, 2, (unsigned char *)&len);
682
683 /* If the RR is shorter than RRBUFLEN (most of them, in practice)
684 then we can just digest it now. If it exceeds RRBUFLEN we have to
685 go back to the start and do it in chunks. */
686 if (j >= RRBUFLEN)
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000687 {
Simon Kelley059aded2020-11-12 23:09:15 +0000688 state.ip = p;
689 state.op = NULL;
690 state.desc = rr_desc;
691
692 for (j = 0; get_rdata(header, plen, &state); j++)
693 {
694 rrbuf[j] = *state.op;
695
696 if (j == RRBUFLEN - 1)
697 {
698 hash->update(ctx, RRBUFLEN, rrbuf);
699 j = -1;
700 }
701 }
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000702 }
Simon Kelley059aded2020-11-12 23:09:15 +0000703
704 if (j != 0)
705 hash->update(ctx, j, rrbuf);
Simon Kelley4e96a4b2020-11-11 23:25:04 +0000706 }
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000707 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000708
709 hash->digest(ctx, hash->digest_size, digest);
710
Simon Kelley5ada8882014-01-09 22:25:03 +0000711 /* namebuff used for workspace above, restore to leave unchanged on exit */
712 p = (unsigned char*)(rrset[0]);
Simon Kelley394ff492015-03-29 22:17:14 +0100713 extract_name(header, plen, &p, name, 1, 0);
Simon Kelley5ada8882014-01-09 22:25:03 +0000714
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000715 if (key)
716 {
717 if (algo_in == algo && keytag_in == key_tag &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000718 verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000719 return STAT_SECURE;
720 }
721 else
722 {
723 /* iterate through all possible keys 4035 5.3.1 */
724 for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
Simon Kelleycc921df2019-01-02 22:48:59 +0000725 if (crecp->addr.key.algo == algo &&
726 crecp->addr.key.keytag == key_tag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000727 crecp->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000728 verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5107ace2014-02-23 10:48:32 +0000729 return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000730 }
731 }
732
733 return STAT_BOGUS;
734}
735
Simon Kelley2dbba342015-12-16 13:41:58 +0000736
Simon Kelley0fc2f312014-01-08 10:26:58 +0000737/* The DNS packet is expected to contain the answer to a DNSKEY query.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000738 Put all DNSKEYs in the answer which are valid into the cache.
739 return codes:
Simon Kelley3b799c82015-12-17 16:58:04 +0000740 STAT_OK Done, key(s) in cache.
741 STAT_BOGUS No DNSKEYs found, which can be validated with DS,
742 or self-sign for DNSKEY RRset is not valid, bad packet.
743 STAT_NEED_DS DS records to validate a key not found, name in keyname
744 STAT_NEED_KEY DNSKEY records to validate a key not found, name in keyname
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000745*/
746int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
747{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000748 unsigned char *psave, *p = (unsigned char *)(header+1);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000749 struct crec *crecp, *recp1;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100750 int rc, j, qtype, qclass, rdlen, flags, algo, valid, keytag;
751 unsigned long ttl, sig_ttl;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000752 struct blockdata *key;
Simon Kelleycc921df2019-01-02 22:48:59 +0000753 union all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000754
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000755 if (ntohs(header->qdcount) != 1 ||
Simon Kelley19b0e3b2019-10-12 21:54:37 +0100756 RCODE(header) == SERVFAIL || RCODE(header) == REFUSED ||
Simon Kelley394ff492015-03-29 22:17:14 +0100757 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +0000758 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000759
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000760 GETSHORT(qtype, p);
761 GETSHORT(qclass, p);
762
Simon Kelley97e618a2015-01-07 21:55:43 +0000763 if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000764 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000765
Simon Kelleyb8eac192014-02-27 14:30:03 +0000766 /* See if we have cached a DS record which validates this key */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000767 if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
768 {
769 strcpy(keyname, name);
770 return STAT_NEED_DS;
771 }
Simon Kelleyb8eac192014-02-27 14:30:03 +0000772
Simon Kelley0fc2f312014-01-08 10:26:58 +0000773 /* NOTE, we need to find ONE DNSKEY which matches the DS */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000774 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000775 {
776 /* Ensure we have type, class TTL and length */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000777 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +0000778 return STAT_BOGUS; /* bad packet */
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000779
780 GETSHORT(qtype, p);
781 GETSHORT(qclass, p);
782 GETLONG(ttl, p);
783 GETSHORT(rdlen, p);
Simon Kelley6f468102014-01-26 23:39:17 +0000784
Simon Kelley0fc2f312014-01-08 10:26:58 +0000785 if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000786 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000787
Simon Kelley6f468102014-01-26 23:39:17 +0000788 if (qclass != class || qtype != T_DNSKEY || rc == 2)
789 {
790 p += rdlen;
791 continue;
792 }
793
Simon Kelley0fc2f312014-01-08 10:26:58 +0000794 psave = p;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000795
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000796 GETSHORT(flags, p);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000797 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000798 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000799 algo = *p++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000800 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000801 key = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000802
Simon Kelleye7829ae2014-01-22 22:21:51 +0000803 /* key must have zone key flag set */
804 if (flags & 0x100)
805 key = blockdata_alloc((char*)p, rdlen - 4);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000806
807 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000808
Simon Kelley0fc2f312014-01-08 10:26:58 +0000809 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000810 {
811 if (key)
812 blockdata_free(key);
Simon Kelley87070192014-03-01 20:48:24 +0000813 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000814 }
815
Simon Kelleye7829ae2014-01-22 22:21:51 +0000816 /* No zone key flag or malloc failure */
817 if (!key)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000818 continue;
819
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000820 for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000821 {
822 void *ctx;
823 unsigned char *digest, *ds_digest;
824 const struct nettle_hash *hash;
Simon Kelley9a31b682015-12-15 10:20:39 +0000825 int sigcnt, rrcnt;
826
Simon Kelleycc921df2019-01-02 22:48:59 +0000827 if (recp1->addr.ds.algo == algo &&
828 recp1->addr.ds.keytag == keytag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000829 recp1->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000830 (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
Simon Kelley86bec2d2014-01-13 21:31:20 +0000831 hash_init(hash, &ctx, &digest))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000832
Simon Kelley86bec2d2014-01-13 21:31:20 +0000833 {
834 int wire_len = to_wire(name);
835
836 /* Note that digest may be different between DSs, so
837 we can't move this outside the loop. */
838 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
839 hash->update(ctx, (unsigned int)rdlen, psave);
840 hash->digest(ctx, hash->digest_size, digest);
841
842 from_wire(name);
843
Simon Kelley9a31b682015-12-15 10:20:39 +0000844 if (!(recp1->flags & F_NEG) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000845 recp1->addr.ds.keylen == (int)hash->digest_size &&
846 (ds_digest = blockdata_retrieve(recp1->addr.ds.keydata, recp1->addr.ds.keylen, NULL)) &&
847 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
Simon Kelley9a31b682015-12-15 10:20:39 +0000848 explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
849 sigcnt != 0 && rrcnt != 0 &&
850 validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100851 NULL, key, rdlen - 4, algo, keytag, &sig_ttl) == STAT_SECURE)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000852 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000853 valid = 1;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000854 break;
855 }
856 }
857 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000858 blockdata_free(key);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000859 }
860
861 if (valid)
862 {
Simon Kelley93be5b12015-12-15 12:04:40 +0000863 /* DNSKEY RRset determined to be OK, now cache it. */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000864 cache_start_insert();
865
866 p = skip_questions(header, plen);
867
868 for (j = ntohs(header->ancount); j != 0; j--)
869 {
870 /* Ensure we have type, class TTL and length */
871 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +0000872 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000873
874 GETSHORT(qtype, p);
875 GETSHORT(qclass, p);
876 GETLONG(ttl, p);
877 GETSHORT(rdlen, p);
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100878
879 /* TTL may be limited by sig. */
880 if (sig_ttl < ttl)
881 ttl = sig_ttl;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000882
883 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000884 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000885
Simon Kelley8d718cb2014-02-03 16:27:37 +0000886 if (qclass == class && rc == 1)
Simon Kelleye7829ae2014-01-22 22:21:51 +0000887 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000888 psave = p;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000889
Simon Kelley8d718cb2014-02-03 16:27:37 +0000890 if (qtype == T_DNSKEY)
891 {
892 if (rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000893 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000894
895 GETSHORT(flags, p);
896 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000897 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000898 algo = *p++;
899 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
900
Simon Kelley8d718cb2014-02-03 16:27:37 +0000901 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
902 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000903 a.key.keylen = rdlen - 4;
904 a.key.keydata = key;
905 a.key.algo = algo;
906 a.key.keytag = keytag;
907 a.key.flags = flags;
Simon Kelleyab194ed2019-01-01 01:35:30 +0000908
909 if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK))
Simon Kelley93be5b12015-12-15 12:04:40 +0000910 {
911 blockdata_free(key);
912 return STAT_BOGUS;
913 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000914 else
915 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000916 a.log.keytag = keytag;
917 a.log.algo = algo;
Simon Kelleyb77efc12017-10-27 23:23:53 +0100918 if (algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +0000919 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +0000920 else
Simon Kelley15379ea2015-12-21 18:31:55 +0000921 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
Simon Kelley8d718cb2014-02-03 16:27:37 +0000922 }
923 }
924 }
Simon Kelley93be5b12015-12-15 12:04:40 +0000925
Simon Kelley8d718cb2014-02-03 16:27:37 +0000926 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000927 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000928
Simon Kelleye7829ae2014-01-22 22:21:51 +0000929 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000930 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000931 }
932
Simon Kelley0fc2f312014-01-08 10:26:58 +0000933 /* commit cache insert. */
934 cache_end_insert();
Simon Kelley9a31b682015-12-15 10:20:39 +0000935 return STAT_OK;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000936 }
937
Simon Kelley25cf5e32015-01-09 15:53:03 +0000938 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
Simon Kelley0fc2f312014-01-08 10:26:58 +0000939 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000940}
Simon Kelley0fc2f312014-01-08 10:26:58 +0000941
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000942/* The DNS packet is expected to contain the answer to a DS query
943 Put all DSs in the answer which are valid into the cache.
Simon Kelley9a31b682015-12-15 10:20:39 +0000944 Also handles replies which prove that there's no DS at this location,
945 either because the zone is unsigned or this isn't a zone cut. These are
946 cached too.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000947 return codes:
Simon Kelley9a31b682015-12-15 10:20:39 +0000948 STAT_OK At least one valid DS found and in cache.
Simon Kelley97e618a2015-01-07 21:55:43 +0000949 STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000950 STAT_NEED_KEY DNSKEY records to validate a DS not found, name in keyname
Simon Kelley9a31b682015-12-15 10:20:39 +0000951 STAT_NEED_DS DS record needed.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000952*/
953
954int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
955{
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000956 unsigned char *p = (unsigned char *)(header+1);
Simon Kelleyfef2f1c2019-08-29 21:59:00 +0100957 int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0;
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000958 int aclass, atype, rdlen;
959 unsigned long ttl;
Simon Kelleycc921df2019-01-02 22:48:59 +0000960 union all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000961
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000962 if (ntohs(header->qdcount) != 1 ||
Simon Kelleyb8eac192014-02-27 14:30:03 +0000963 !(p = skip_name(p, header, plen, 4)))
Simon Kelley87070192014-03-01 20:48:24 +0000964 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000965
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000966 GETSHORT(qtype, p);
967 GETSHORT(qclass, p);
968
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000969 if (qtype != T_DS || qclass != class)
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000970 rc = STAT_BOGUS;
Simon Kelleyb47b04c2014-02-25 23:13:28 +0000971 else
Simon Kelleyfef2f1c2019-08-29 21:59:00 +0100972 rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl);
Simon Kelley97e618a2015-01-07 21:55:43 +0000973
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000974 if (rc == STAT_INSECURE)
Simon Kelley7f008432018-04-15 20:01:49 +0100975 {
Kevin Darbyshire-Bryantc65b77c2019-05-11 17:05:23 +0000976 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 +0100977 rc = STAT_BOGUS;
978 }
979
Simon Kelleyb8eac192014-02-27 14:30:03 +0000980 p = (unsigned char *)(header+1);
Simon Kelley394ff492015-03-29 22:17:14 +0100981 extract_name(header, plen, &p, name, 1, 4);
Simon Kelleyb8eac192014-02-27 14:30:03 +0000982 p += 4; /* qtype, qclass */
983
Simon Kelley0b8a5a32015-03-27 11:44:55 +0000984 /* If the key needed to validate the DS is on the same domain as the DS, we'll
985 loop getting nowhere. Stop that now. This can happen of the DS answer comes
986 from the DS's zone, and not the parent zone. */
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000987 if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
Simon Kelleyb8eac192014-02-27 14:30:03 +0000988 {
Simon Kelley25cf5e32015-01-09 15:53:03 +0000989 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
Simon Kelley97e618a2015-01-07 21:55:43 +0000990 return STAT_BOGUS;
991 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000992
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000993 if (rc != STAT_SECURE)
994 return rc;
995
996 if (!neganswer)
Simon Kelley97e618a2015-01-07 21:55:43 +0000997 {
Simon Kelleyd64c81f2015-12-15 16:11:06 +0000998 cache_start_insert();
999
1000 for (i = 0; i < ntohs(header->ancount); i++)
1001 {
1002 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
1003 return STAT_BOGUS; /* bad packet */
1004
1005 GETSHORT(atype, p);
1006 GETSHORT(aclass, p);
1007 GETLONG(ttl, p);
1008 GETSHORT(rdlen, p);
1009
1010 if (!CHECK_LEN(header, p, plen, rdlen))
1011 return STAT_BOGUS; /* bad packet */
1012
1013 if (aclass == class && atype == T_DS && rc == 1)
1014 {
1015 int algo, digest, keytag;
1016 unsigned char *psave = p;
1017 struct blockdata *key;
Simon Kelleyab194ed2019-01-01 01:35:30 +00001018
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001019 if (rdlen < 4)
1020 return STAT_BOGUS; /* bad packet */
1021
1022 GETSHORT(keytag, p);
1023 algo = *p++;
1024 digest = *p++;
1025
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001026 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
1027 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001028 a.ds.digest = digest;
1029 a.ds.keydata = key;
1030 a.ds.algo = algo;
1031 a.ds.keytag = keytag;
1032 a.ds.keylen = rdlen - 4;
Simon Kelleyab194ed2019-01-01 01:35:30 +00001033
1034 if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001035 {
1036 blockdata_free(key);
1037 return STAT_BOGUS;
1038 }
1039 else
1040 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001041 a.log.keytag = keytag;
1042 a.log.algo = algo;
1043 a.log.digest = digest;
Simon Kelleyb77efc12017-10-27 23:23:53 +01001044 if (ds_digest_name(digest) && algo_digest_name(algo))
Simon Kelley15379ea2015-12-21 18:31:55 +00001045 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001046 else
Simon Kelley15379ea2015-12-21 18:31:55 +00001047 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 +00001048 }
1049 }
1050
1051 p = psave;
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001052 }
Simon Kelley3b799c82015-12-17 16:58:04 +00001053 if (!ADD_RDLEN(header, p, plen, rdlen))
1054 return STAT_BOGUS; /* bad packet */
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001055 }
Simon Kelley3b799c82015-12-17 16:58:04 +00001056
1057 cache_end_insert();
1058
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001059 }
1060 else
1061 {
1062 int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001063
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001064 if (RCODE(header) == NXDOMAIN)
1065 flags |= F_NXDOMAIN;
1066
Simon Kelley97e618a2015-01-07 21:55:43 +00001067 /* We only cache validated DS records, DNSSECOK flag hijacked
1068 to store presence/absence of NS. */
1069 if (nons)
1070 flags &= ~F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001071
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001072 cache_start_insert();
Simon Kelleyb8eac192014-02-27 14:30:03 +00001073
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001074 /* Use TTL from NSEC for negative cache entries */
1075 if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
1076 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001077
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001078 cache_end_insert();
1079
Simon Kelley532246f2020-04-04 18:50:56 +01001080 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS");
Simon Kelleyb8eac192014-02-27 14:30:03 +00001081 }
Simon Kelleyd64c81f2015-12-15 16:11:06 +00001082
Simon Kelley9a31b682015-12-15 10:20:39 +00001083 return STAT_OK;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001084}
1085
Simon Kelley9a31b682015-12-15 10:20:39 +00001086
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001087/* 4034 6.1 */
1088static int hostname_cmp(const char *a, const char *b)
1089{
Simon Kelleydbf72122014-01-21 14:28:02 +00001090 char *sa, *ea, *ca, *sb, *eb, *cb;
1091 unsigned char ac, bc;
1092
1093 sa = ea = (char *)a + strlen(a);
1094 sb = eb = (char *)b + strlen(b);
1095
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001096 while (1)
1097 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001098 while (sa != a && *(sa-1) != '.')
1099 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001100
Simon Kelleydbf72122014-01-21 14:28:02 +00001101 while (sb != b && *(sb-1) != '.')
1102 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001103
Simon Kelleydbf72122014-01-21 14:28:02 +00001104 ca = sa;
1105 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001106
Simon Kelleydbf72122014-01-21 14:28:02 +00001107 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001108 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001109 if (ca == ea)
1110 {
1111 if (cb == eb)
1112 break;
1113
1114 return -1;
1115 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001116
Simon Kelleydbf72122014-01-21 14:28:02 +00001117 if (cb == eb)
1118 return 1;
1119
1120 ac = (unsigned char) *ca++;
1121 bc = (unsigned char) *cb++;
1122
1123 if (ac >= 'A' && ac <= 'Z')
1124 ac += 'a' - 'A';
1125 if (bc >= 'A' && bc <= 'Z')
1126 bc += 'a' - 'A';
1127
Simon Kelley979cdf92014-01-21 16:26:41 +00001128 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001129 return -1;
1130 else if (ac != bc)
1131 return 1;
1132 }
1133
1134
1135 if (sa == a)
1136 {
1137 if (sb == b)
1138 return 0;
1139
1140 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001141 }
1142
Simon Kelleydbf72122014-01-21 14:28:02 +00001143 if (sb == b)
1144 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001145
Simon Kelley3e86d312015-12-20 20:50:05 +00001146 ea = --sa;
1147 eb = --sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001148 }
1149}
1150
Simon Kelley4fe67442018-01-19 12:26:08 +00001151static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
1152 char *workspace1_in, char *workspace2, char *name, int type, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001153{
1154 int i, rc, rdlen;
1155 unsigned char *p, *psave;
1156 int offset = (type & 0xff) >> 3;
1157 int mask = 0x80 >> (type & 0x07);
Simon Kelley97e618a2015-01-07 21:55:43 +00001158
1159 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001160 *nons = 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001161
1162 /* Find NSEC record that proves name doesn't exist */
1163 for (i = 0; i < nsec_count; i++)
1164 {
Simon Kelley4fe67442018-01-19 12:26:08 +00001165 char *workspace1 = workspace1_in;
1166 int sig_labels, name_labels;
1167
Simon Kelley5107ace2014-02-23 10:48:32 +00001168 p = nsecs[i];
Simon Kelley394ff492015-03-29 22:17:14 +01001169 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001170 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001171 p += 8; /* class, type, TTL */
1172 GETSHORT(rdlen, p);
1173 psave = p;
Simon Kelley394ff492015-03-29 22:17:14 +01001174 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001175 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001176
1177 /* If NSEC comes from wildcard expansion, use original wildcard
1178 as name for computation. */
1179 sig_labels = *labels[i];
1180 name_labels = count_labels(workspace1);
1181
1182 if (sig_labels < name_labels)
1183 {
1184 int k;
1185 for (k = name_labels - sig_labels; k != 0; k--)
1186 {
1187 while (*workspace1 != '.' && *workspace1 != 0)
1188 workspace1++;
1189 if (k != 1 && *workspace1 == '.')
1190 workspace1++;
1191 }
1192
1193 workspace1--;
1194 *workspace1 = '*';
1195 }
1196
Simon Kelley5107ace2014-02-23 10:48:32 +00001197 rc = hostname_cmp(workspace1, name);
1198
1199 if (rc == 0)
1200 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001201 /* 4035 para 5.4. Last sentence */
1202 if (type == T_NSEC || type == T_RRSIG)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001203 return 1;
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001204
Simon Kelley5107ace2014-02-23 10:48:32 +00001205 /* NSEC with the same name as the RR we're testing, check
1206 that the type in question doesn't appear in the type map */
1207 rdlen -= p - psave;
1208 /* rdlen is now length of type map, and p points to it */
1209
Simon Kelley97e618a2015-01-07 21:55:43 +00001210 /* If we can prove that there's no NS record, return that information. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001211 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
1212 *nons = 0;
Simon Kelley97e618a2015-01-07 21:55:43 +00001213
Simon Kelley9a31b682015-12-15 10:20:39 +00001214 if (rdlen >= 2 && p[0] == 0)
1215 {
1216 /* A CNAME answer would also be valid, so if there's a CNAME is should
1217 have been returned. */
1218 if ((p[2] & (0x80 >> T_CNAME)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001219 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001220
1221 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001222 DS from the wrong side of the delegation. For the root DS,
1223 this is expected. */
1224 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001225 return 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001226 }
1227
Simon Kelley5107ace2014-02-23 10:48:32 +00001228 while (rdlen >= 2)
1229 {
1230 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001231 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001232
1233 if (p[0] == type >> 8)
1234 {
1235 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001236 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001237 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001238
Josh Soref730c6742017-02-06 16:14:04 +00001239 break; /* finished checking */
Simon Kelley5107ace2014-02-23 10:48:32 +00001240 }
1241
1242 rdlen -= p[1];
1243 p += p[1];
1244 }
1245
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001246 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001247 }
1248 else if (rc == -1)
1249 {
1250 /* Normal case, name falls between NSEC name and next domain name,
1251 wrap around case, name falls between NSEC name (rc == -1) and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001252 if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001253 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001254 }
1255 else
1256 {
1257 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001258 if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001259 return 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001260 }
1261 }
1262
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001263 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001264}
1265
1266/* return digest length, or zero on error */
1267static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1268 unsigned char *salt, int salt_len, int iterations)
1269{
1270 void *ctx;
1271 unsigned char *digest;
1272 int i;
1273
1274 if (!hash_init(hash, &ctx, &digest))
1275 return 0;
1276
1277 hash->update(ctx, to_wire(in), (unsigned char *)in);
1278 hash->update(ctx, salt_len, salt);
1279 hash->digest(ctx, hash->digest_size, digest);
1280
1281 for(i = 0; i < iterations; i++)
1282 {
1283 hash->update(ctx, hash->digest_size, digest);
1284 hash->update(ctx, salt_len, salt);
1285 hash->digest(ctx, hash->digest_size, digest);
1286 }
1287
1288 from_wire(in);
1289
1290 *out = digest;
1291 return hash->digest_size;
1292}
1293
1294/* Decode base32 to first "." or end of string */
1295static int base32_decode(char *in, unsigned char *out)
1296{
Simon Kelleya857daa2014-02-24 21:01:09 +00001297 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001298 unsigned char *p = out;
1299
Simon Kelleya857daa2014-02-24 21:01:09 +00001300 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001301 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001302 if (c >= '0' && c <= '9')
1303 c -= '0';
1304 else if (c >= 'a' && c <= 'v')
1305 c -= 'a', c += 10;
1306 else if (c >= 'A' && c <= 'V')
1307 c -= 'A', c += 10;
1308 else
1309 return 0;
1310
1311 for (mask = 0x10, i = 0; i < 5; i++)
1312 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001313 if (c & mask)
1314 oc |= 1;
1315 mask = mask >> 1;
1316 if (((++on) & 7) == 0)
1317 *p++ = oc;
1318 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001319 }
1320 }
1321
1322 if ((on & 7) != 0)
1323 return 0;
1324
1325 return p - out;
1326}
1327
Simon Kelleyfbc52052014-12-23 15:46:08 +00001328static 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 +00001329 char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001330{
Simon Kelley9a31b682015-12-15 10:20:39 +00001331 int i, hash_len, salt_len, base32_len, rdlen, flags;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001332 unsigned char *p, *psave;
1333
1334 for (i = 0; i < nsec_count; i++)
1335 if ((p = nsecs[i]))
1336 {
Simon Kelley394ff492015-03-29 22:17:14 +01001337 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleyfbc52052014-12-23 15:46:08 +00001338 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
1339 return 0;
1340
1341 p += 8; /* class, type, TTL */
1342 GETSHORT(rdlen, p);
1343 psave = p;
Simon Kelley9a31b682015-12-15 10:20:39 +00001344 p++; /* algo */
1345 flags = *p++; /* flags */
1346 p += 2; /* iterations */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001347 salt_len = *p++; /* salt_len */
1348 p += salt_len; /* salt */
1349 hash_len = *p++; /* p now points to next hashed name */
1350
1351 if (!CHECK_LEN(header, p, plen, hash_len))
1352 return 0;
1353
1354 if (digest_len == base32_len && hash_len == base32_len)
1355 {
1356 int rc = memcmp(workspace2, digest, digest_len);
1357
1358 if (rc == 0)
1359 {
1360 /* We found an NSEC3 whose hashed name exactly matches the query, so
1361 we just need to check the type map. p points to the RR data for the record. */
1362
1363 int offset = (type & 0xff) >> 3;
1364 int mask = 0x80 >> (type & 0x07);
1365
1366 p += hash_len; /* skip next-domain hash */
1367 rdlen -= p - psave;
1368
1369 if (!CHECK_LEN(header, p, plen, rdlen))
1370 return 0;
1371
Simon Kelley9a31b682015-12-15 10:20:39 +00001372 if (rdlen >= 2 && p[0] == 0)
1373 {
Simon Kelleyec0628c2015-12-31 20:55:39 +00001374 /* If we can prove that there's no NS record, return that information. */
1375 if (nons && (p[2] & (0x80 >> T_NS)) != 0)
1376 *nons = 0;
1377
Simon Kelley9a31b682015-12-15 10:20:39 +00001378 /* A CNAME answer would also be valid, so if there's a CNAME is should
1379 have been returned. */
1380 if ((p[2] & (0x80 >> T_CNAME)) != 0)
1381 return 0;
1382
1383 /* If the SOA bit is set for a DS record, then we have the
Simon Kelleya969ba62018-01-20 23:08:38 +00001384 DS from the wrong side of the delegation. For the root DS,
1385 this is expected. */
1386 if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001387 return 0;
1388 }
1389
Simon Kelleyfbc52052014-12-23 15:46:08 +00001390 while (rdlen >= 2)
1391 {
1392 if (p[0] == type >> 8)
1393 {
1394 /* Does the NSEC3 say our type exists? */
1395 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001396 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001397
Josh Soref730c6742017-02-06 16:14:04 +00001398 break; /* finished checking */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001399 }
1400
1401 rdlen -= p[1];
1402 p += p[1];
1403 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001404
Simon Kelleyfbc52052014-12-23 15:46:08 +00001405 return 1;
1406 }
Simon Kelley4d25cf82015-06-06 23:13:57 +01001407 else if (rc < 0)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001408 {
1409 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1410 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001411 if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001412 {
1413 if ((flags & 0x01) && nons) /* opt out */
1414 *nons = 0;
1415
1416 return 1;
1417 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001418 }
1419 else
1420 {
1421 /* wrap around case, name falls between start and next domain name */
Simon Kelley4d25cf82015-06-06 23:13:57 +01001422 if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
Simon Kelley9a31b682015-12-15 10:20:39 +00001423 {
1424 if ((flags & 0x01) && nons) /* opt out */
1425 *nons = 0;
1426
1427 return 1;
1428 }
Simon Kelleyfbc52052014-12-23 15:46:08 +00001429 }
1430 }
1431 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001432
Simon Kelleyfbc52052014-12-23 15:46:08 +00001433 return 0;
1434}
1435
Simon Kelley24187532014-02-24 21:46:44 +00001436static 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 +00001437 char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001438{
Simon Kelleya857daa2014-02-24 21:01:09 +00001439 unsigned char *salt, *p, *digest;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001440 int digest_len, i, iterations, salt_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001441 struct nettle_hash const *hash;
1442 char *closest_encloser, *next_closest, *wildcard;
Simon Kelley97e618a2015-01-07 21:55:43 +00001443
1444 if (nons)
Simon Kelley9a31b682015-12-15 10:20:39 +00001445 *nons = 1;
Simon Kelley97e618a2015-01-07 21:55:43 +00001446
Simon Kelley5107ace2014-02-23 10:48:32 +00001447 /* Look though the NSEC3 records to find the first one with
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001448 an algorithm we support.
Simon Kelley5107ace2014-02-23 10:48:32 +00001449
1450 Take the algo, iterations, and salt of that record
1451 as the ones we're going to use, and prune any
1452 that don't match. */
1453
1454 for (i = 0; i < nsec_count; i++)
1455 {
1456 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001457 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001458
1459 p += 10; /* type, class, TTL, rdlen */
1460 algo = *p++;
1461
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001462 if ((hash = hash_find(nsec3_digest_name(algo))))
Simon Kelley5107ace2014-02-23 10:48:32 +00001463 break; /* known algo */
1464 }
1465
1466 /* No usable NSEC3s */
1467 if (i == nsec_count)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001468 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001469
1470 p++; /* flags */
Simon Kelley40205a02016-03-14 21:24:00 +00001471
Simon Kelley5107ace2014-02-23 10:48:32 +00001472 GETSHORT (iterations, p);
Simon Kelley40205a02016-03-14 21:24:00 +00001473 /* Upper-bound iterations, to avoid DoS.
1474 Strictly, there are lower bounds for small keys, but
1475 since we don't have key size info here, at least limit
1476 to the largest bound, for 4096-bit keys. RFC 5155 10.3 */
1477 if (iterations > 2500)
1478 return 0;
1479
Simon Kelley5107ace2014-02-23 10:48:32 +00001480 salt_len = *p++;
1481 salt = p;
1482 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001483 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001484
1485 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1486 for (i = 0; i < nsec_count; i++)
1487 {
1488 unsigned char *nsec3p = nsecs[i];
Simon Kelleyce5732e2015-12-20 21:39:19 +00001489 int this_iter, flags;
Simon Kelley5107ace2014-02-23 10:48:32 +00001490
1491 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1492
1493 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001494 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001495
1496 p += 10; /* type, class, TTL, rdlen */
1497
1498 if (*p++ != algo)
1499 continue;
1500
Simon Kelleyce5732e2015-12-20 21:39:19 +00001501 flags = *p++; /* flags */
Simon Kelley5107ace2014-02-23 10:48:32 +00001502
Simon Kelleyce5732e2015-12-20 21:39:19 +00001503 /* 5155 8.2 */
1504 if (flags != 0 && flags != 1)
1505 continue;
1506
Simon Kelleya857daa2014-02-24 21:01:09 +00001507 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001508 if (this_iter != iterations)
1509 continue;
1510
1511 if (salt_len != *p++)
1512 continue;
1513
1514 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001515 return 0; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001516
1517 if (memcmp(p, salt, salt_len) != 0)
1518 continue;
1519
1520 /* All match, put the pointer back */
1521 nsecs[i] = nsec3p;
1522 }
1523
Simon Kelleyfbc52052014-12-23 15:46:08 +00001524 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001525 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001526
Simon Kelleya969ba62018-01-20 23:08:38 +00001527 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 +00001528 return 1;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001529
1530 /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
1531 or an answer inferred from a wildcard record. */
Simon Kelley5107ace2014-02-23 10:48:32 +00001532 closest_encloser = name;
1533 next_closest = NULL;
1534
1535 do
1536 {
1537 if (*closest_encloser == '.')
1538 closest_encloser++;
1539
Simon Kelleyfbc52052014-12-23 15:46:08 +00001540 if (wildname && hostname_isequal(closest_encloser, wildname))
1541 break;
1542
Simon Kelleya857daa2014-02-24 21:01:09 +00001543 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001544 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001545
1546 for (i = 0; i < nsec_count; i++)
1547 if ((p = nsecs[i]))
1548 {
Simon Kelley394ff492015-03-29 22:17:14 +01001549 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001550 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001551 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001552
Simon Kelleya857daa2014-02-24 21:01:09 +00001553 if (digest_len == base32_len &&
1554 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001555 break; /* Gotit */
1556 }
1557
1558 if (i != nsec_count)
1559 break;
1560
1561 next_closest = closest_encloser;
1562 }
1563 while ((closest_encloser = strchr(closest_encloser, '.')));
1564
Simon Kelleya7b27e82016-03-16 19:11:52 +00001565 if (!closest_encloser || !next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001566 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001567
Simon Kelley24187532014-02-24 21:46:44 +00001568 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001569 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001570 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001571
Simon Kelleya969ba62018-01-20 23:08:38 +00001572 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001573 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001574
1575 /* Finally, check that there's no seat of wildcard synthesis */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001576 if (!wildname)
1577 {
1578 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001579 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001580
1581 wildcard--;
1582 *wildcard = '*';
1583
1584 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001585 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001586
Simon Kelleya969ba62018-01-20 23:08:38 +00001587 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001588 return 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001589 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001590
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001591 return 1;
1592}
1593
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001594static 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 +00001595{
Simon Kelley4fe67442018-01-19 12:26:08 +00001596 static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
1597 static int nsecset_sz = 0, rrsig_labels_sz = 0;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001598
1599 int type_found = 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001600 unsigned char *auth_start, *p = skip_questions(header, plen);
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001601 int type, class, rdlen, i, nsecs_found;
1602 unsigned long ttl;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001603
1604 /* Move to NS section */
1605 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1606 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001607
1608 auth_start = p;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001609
Simon Kelleye24abf22019-09-03 22:48:39 +01001610 for (nsecs_found = 0, i = 0; i < ntohs(header->nscount); i++)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001611 {
1612 unsigned char *pstart = p;
1613
Simon Kelley4fe67442018-01-19 12:26:08 +00001614 if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001615 return 0;
Simon Kelley4fe67442018-01-19 12:26:08 +00001616
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001617 GETSHORT(type, p);
1618 GETSHORT(class, p);
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001619 GETLONG(ttl, p);
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001620 GETSHORT(rdlen, p);
1621
1622 if (class == qclass && (type == T_NSEC || type == T_NSEC3))
1623 {
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001624 if (nsec_ttl)
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001625 {
1626 /* Limit TTL with sig TTL */
1627 if (daemon->rr_status[ntohs(header->ancount) + i] < ttl)
1628 ttl = daemon->rr_status[ntohs(header->ancount) + i];
1629 *nsec_ttl = ttl;
1630 }
1631
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001632 /* No mixed NSECing 'round here, thankyouverymuch */
1633 if (type_found != 0 && type_found != type)
1634 return 0;
1635
1636 type_found = type;
1637
1638 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1639 return 0;
1640
Simon Kelley4fe67442018-01-19 12:26:08 +00001641 if (type == T_NSEC)
1642 {
1643 /* If we're looking for NSECs, find the corresponding SIGs, to
1644 extract the labels value, which we need in case the NSECs
1645 are the result of wildcard expansion.
1646 Note that the NSEC may not have been validated yet
1647 so if there are multiple SIGs, make sure the label value
1648 is the same in all, to avoid be duped by a rogue one.
1649 If there are no SIGs, that's an error */
1650 unsigned char *p1 = auth_start;
1651 int res, j, rdlen1, type1, class1;
1652
1653 if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
1654 return 0;
1655
1656 rrsig_labels[nsecs_found] = NULL;
1657
1658 for (j = ntohs(header->nscount); j != 0; j--)
1659 {
1660 if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
1661 return 0;
1662
1663 GETSHORT(type1, p1);
1664 GETSHORT(class1, p1);
1665 p1 += 4; /* TTL */
1666 GETSHORT(rdlen1, p1);
1667
1668 if (!CHECK_LEN(header, p1, plen, rdlen1))
1669 return 0;
1670
1671 if (res == 1 && class1 == qclass && type1 == T_RRSIG)
1672 {
1673 int type_covered;
1674 unsigned char *psav = p1;
1675
Simon Kelleycd7df612018-01-20 00:10:55 +00001676 if (rdlen1 < 18)
Simon Kelley4fe67442018-01-19 12:26:08 +00001677 return 0; /* bad packet */
1678
1679 GETSHORT(type_covered, p1);
1680
1681 if (type_covered == T_NSEC)
1682 {
1683 p1++; /* algo */
1684
1685 /* labels field must be the same in every SIG we find. */
1686 if (!rrsig_labels[nsecs_found])
1687 rrsig_labels[nsecs_found] = p1;
1688 else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
1689 return 0;
1690 }
1691 p1 = psav;
1692 }
1693
1694 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1695 return 0;
1696 }
1697
1698 /* Must have found at least one sig. */
1699 if (!rrsig_labels[nsecs_found])
1700 return 0;
1701 }
1702
1703 nsecset[nsecs_found++] = pstart;
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001704 }
1705
1706 if (!ADD_RDLEN(header, p, plen, rdlen))
1707 return 0;
1708 }
1709
1710 if (type_found == T_NSEC)
Simon Kelley4fe67442018-01-19 12:26:08 +00001711 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 +00001712 else if (type_found == T_NSEC3)
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001713 return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001714 else
1715 return 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001716}
Simon Kelley9a31b682015-12-15 10:20:39 +00001717
1718/* Check signing status of name.
1719 returns:
Simon Kelley3b799c82015-12-17 16:58:04 +00001720 STAT_SECURE zone is signed.
1721 STAT_INSECURE zone proved unsigned.
1722 STAT_NEED_DS require DS record of name returned in keyname.
1723 STAT_NEED_KEY require DNSKEY record of name returned in keyname.
Simon Kelley9a31b682015-12-15 10:20:39 +00001724 name returned unaltered.
1725*/
1726static int zone_status(char *name, int class, char *keyname, time_t now)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001727{
Simon Kelleya63b8b82016-01-12 11:28:58 +00001728 int name_start = strlen(name); /* for when TA is root */
Simon Kelley9a31b682015-12-15 10:20:39 +00001729 struct crec *crecp;
1730 char *p;
Simon Kelleya63b8b82016-01-12 11:28:58 +00001731
1732 /* First, work towards the root, looking for a trust anchor.
1733 This can either be one configured, or one previously cached.
1734 We can assume, if we don't find one first, that there is
1735 a trust anchor at the root. */
1736 for (p = name; p; p = strchr(p, '.'))
1737 {
1738 if (*p == '.')
1739 p++;
1740
1741 if (cache_find_by_name(NULL, p, now, F_DS))
1742 {
1743 name_start = p - name;
1744 break;
1745 }
1746 }
Simon Kelley367341f2016-01-12 15:58:23 +00001747
Simon Kelleya63b8b82016-01-12 11:28:58 +00001748 /* Now work away from the trust anchor */
Simon Kelley9a31b682015-12-15 10:20:39 +00001749 while (1)
1750 {
1751 strcpy(keyname, &name[name_start]);
1752
1753 if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
1754 return STAT_NEED_DS;
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001755
Josh Soref730c6742017-02-06 16:14:04 +00001756 /* F_DNSSECOK misused in DS cache records to non-existence of NS record.
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001757 F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
1758 but that's because there's no NS record either, ie this isn't the start
1759 of a zone. We only prove that the DNS tree below a node is unsigned when
1760 we prove that we're at a zone cut AND there's no DS record. */
1761 if (crecp->flags & F_NEG)
1762 {
1763 if (crecp->flags & F_DNSSECOK)
1764 return STAT_INSECURE; /* proved no DS here */
1765 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001766 else
Simon Kelley2dbba342015-12-16 13:41:58 +00001767 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001768 /* If all the DS records have digest and/or sig algos we don't support,
1769 then the zone is insecure. Note that if an algo
1770 appears in the DS, then RRSIGs for that algo MUST
1771 exist for each RRset: 4035 para 2.2 So if we find
1772 a DS here with digest and sig we can do, we're entitled
1773 to assume we can validate the zone and if we can't later,
1774 because an RRSIG is missing we return BOGUS.
1775 */
Simon Kelley2dbba342015-12-16 13:41:58 +00001776 do
1777 {
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001778 if (crecp->uid == (unsigned int)class &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001779 ds_digest_name(crecp->addr.ds.digest) &&
1780 algo_digest_name(crecp->addr.ds.algo))
Simon Kelleya86fdf42015-12-20 21:19:20 +00001781 break;
Simon Kelley2dbba342015-12-16 13:41:58 +00001782 }
1783 while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
Simon Kelley2dbba342015-12-16 13:41:58 +00001784
Simon Kelleya86fdf42015-12-20 21:19:20 +00001785 if (!crecp)
Simon Kelleyd67ecac2015-12-20 20:44:23 +00001786 return STAT_INSECURE;
Simon Kelley2dbba342015-12-16 13:41:58 +00001787 }
1788
Simon Kelley9a31b682015-12-15 10:20:39 +00001789 if (name_start == 0)
1790 break;
1791
1792 for (p = &name[name_start-2]; (*p != '.') && (p != name); p--);
1793
1794 if (p != name)
1795 p++;
1796
1797 name_start = p - name;
1798 }
1799
1800 return STAT_SECURE;
1801}
1802
1803/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3)
1804 Return code:
1805 STAT_SECURE if it validates.
1806 STAT_INSECURE at least one RRset not validated, because in unsigned zone.
1807 STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
1808 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
Simon Kelleya6004d72017-10-25 17:48:19 +01001809 STAT_NEED_DS need DS to complete validation (name is returned in keyname)
1810
Simon Kelley373e9172017-12-01 22:40:56 +00001811 daemon->rr_status points to a char array which corressponds to the RRs in the
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001812 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 +01001813
1814 When validating replies to DS records, we're only interested in the NSEC{3} RRs in the auth section.
1815 Other RRs in that section missing sigs will not cause am INSECURE reply. We determine this mode
1816 is the nons argument is non-NULL.
Simon Kelley9a31b682015-12-15 10:20:39 +00001817*/
1818int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001819 int *class, int check_unsigned, int *neganswer, int *nons, int *nsec_ttl)
Simon Kelley9a31b682015-12-15 10:20:39 +00001820{
1821 static unsigned char **targets = NULL;
1822 static int target_sz = 0;
1823
Simon Kelleyb40f26c2015-12-17 11:57:26 +00001824 unsigned char *ans_start, *p1, *p2;
Simon Kelleya6004d72017-10-25 17:48:19 +01001825 int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
Simon Kelley91421cb2018-10-18 19:21:55 +01001826 int i, j, rc = STAT_INSECURE;
Simon Kelleya6004d72017-10-25 17:48:19 +01001827 int secure = STAT_SECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001828
Simon Kelley373e9172017-12-01 22:40:56 +00001829 /* extend rr_status if necessary */
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001830 if (daemon->rr_status_sz < ntohs(header->ancount) + ntohs(header->nscount))
Simon Kelley373e9172017-12-01 22:40:56 +00001831 {
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001832 unsigned long *new = whine_malloc(sizeof(*daemon->rr_status) * (ntohs(header->ancount) + ntohs(header->nscount) + 64));
Simon Kelley373e9172017-12-01 22:40:56 +00001833
1834 if (!new)
1835 return STAT_BOGUS;
1836
1837 free(daemon->rr_status);
1838 daemon->rr_status = new;
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001839 daemon->rr_status_sz = ntohs(header->ancount) + ntohs(header->nscount) + 64;
Simon Kelley373e9172017-12-01 22:40:56 +00001840 }
1841
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001842 memset(daemon->rr_status, 0, sizeof(*daemon->rr_status) * daemon->rr_status_sz);
Simon Kelleya6004d72017-10-25 17:48:19 +01001843
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001844 if (neganswer)
1845 *neganswer = 0;
1846
Simon Kelley87070192014-03-01 20:48:24 +00001847 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001848 return STAT_BOGUS;
1849
Simon Kelley87070192014-03-01 20:48:24 +00001850 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001851 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001852
Simon Kelley9a31b682015-12-15 10:20:39 +00001853 p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001854
Simon Kelley9a31b682015-12-15 10:20:39 +00001855 /* Find all the targets we're looking for answers to.
1856 The zeroth array element is for the query, subsequent ones
1857 for CNAME targets, unless the query is for a CNAME. */
1858
1859 if (!expand_workspace(&targets, &target_sz, 0))
1860 return STAT_BOGUS;
1861
1862 targets[0] = p1;
1863 targetidx = 1;
1864
Simon Kelley394ff492015-03-29 22:17:14 +01001865 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001866 return STAT_BOGUS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001867
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001868 GETSHORT(qtype, p1);
1869 GETSHORT(qclass, p1);
1870 ans_start = p1;
1871
Simon Kelley9a31b682015-12-15 10:20:39 +00001872 /* Can't validate an RRSIG query */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001873 if (qtype == T_RRSIG)
1874 return STAT_INSECURE;
Simon Kelleye3ec6f02015-06-12 21:39:11 +01001875
Simon Kelley9a31b682015-12-15 10:20:39 +00001876 if (qtype != T_CNAME)
1877 for (j = ntohs(header->ancount); j != 0; j--)
1878 {
1879 if (!(p1 = skip_name(p1, header, plen, 10)))
1880 return STAT_BOGUS; /* bad packet */
1881
1882 GETSHORT(type2, p1);
1883 p1 += 6; /* class, TTL */
1884 GETSHORT(rdlen2, p1);
1885
1886 if (type2 == T_CNAME)
1887 {
1888 if (!expand_workspace(&targets, &target_sz, targetidx))
1889 return STAT_BOGUS;
1890
1891 targets[targetidx++] = p1; /* pointer to target name */
1892 }
1893
1894 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1895 return STAT_BOGUS;
1896 }
1897
Simon Kelley0fc2f312014-01-08 10:26:58 +00001898 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001899 {
Simon Kelley91421cb2018-10-18 19:21:55 +01001900 if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
1901 return STAT_BOGUS;
1902
1903 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001904 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001905
1906 GETSHORT(type1, p1);
1907 GETSHORT(class1, p1);
1908 p1 += 4; /* TTL */
1909 GETSHORT(rdlen1, p1);
1910
1911 /* Don't try and validate RRSIGs! */
Simon Kelleya6004d72017-10-25 17:48:19 +01001912 if (type1 == T_RRSIG)
1913 continue;
1914
1915 /* Check if we've done this RRset already */
1916 for (p2 = ans_start, j = 0; j < i; j++)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001917 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001918 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1919 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001920
Simon Kelleya6004d72017-10-25 17:48:19 +01001921 GETSHORT(type2, p2);
1922 GETSHORT(class2, p2);
1923 p2 += 4; /* TTL */
1924 GETSHORT(rdlen2, p2);
1925
1926 if (type2 == type1 && class2 == class1 && rc == 1)
1927 break; /* Done it before: name, type, class all match. */
1928
1929 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1930 return STAT_BOGUS;
1931 }
1932
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001933 /* Done already: copy the validation status */
Simon Kelleya6004d72017-10-25 17:48:19 +01001934 if (j != i)
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001935 daemon->rr_status[i] = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +01001936 else
1937 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001938 /* Not done, validate now */
Simon Kelleya6004d72017-10-25 17:48:19 +01001939 int sigcnt, rrcnt;
1940 char *wildname;
1941
1942 if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
1943 return STAT_BOGUS;
1944
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001945 /* 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 +01001946 if (sigcnt == 0)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001947 {
Simon Kelley69a04772019-09-03 16:49:02 +01001948 /* NSEC and NSEC3 records must be signed. We make this assumption elsewhere. */
1949 if (type1 == T_NSEC || type1 == T_NSEC3)
1950 rc = STAT_INSECURE;
1951 else if (nons && i >= ntohs(header->ancount))
1952 /* If we're validating a DS reply, rather than looking for the value of AD bit,
1953 we only care that NSEC and NSEC3 RRs in the auth section are signed.
1954 Return SECURE even if others (SOA....) are not. */
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001955 rc = STAT_SECURE;
1956 else
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001957 {
Simon Kelley69a04772019-09-03 16:49:02 +01001958 /* unsigned RRsets in auth section are not BOGUS, but do make reply insecure. */
1959 if (check_unsigned && i < ntohs(header->ancount))
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001960 {
1961 rc = zone_status(name, class1, keyname, now);
1962 if (rc == STAT_SECURE)
1963 rc = STAT_BOGUS;
1964 if (class)
1965 *class = class1; /* Class for NEED_DS or NEED_KEY */
1966 }
1967 else
1968 rc = STAT_INSECURE;
1969
1970 if (rc != STAT_INSECURE)
1971 return rc;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001972 }
Simon Kelleya6004d72017-10-25 17:48:19 +01001973 }
1974 else
1975 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001976 /* explore_rrset() gives us key name from sigs in keyname.
1977 Can't overwrite name here. */
1978 strcpy(daemon->workspacename, keyname);
1979 rc = zone_status(daemon->workspacename, class1, keyname, now);
Simon Kelleya6004d72017-10-25 17:48:19 +01001980
1981 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001982 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001983 if (class)
Simon Kelley3b799c82015-12-17 16:58:04 +00001984 *class = class1; /* Class for NEED_DS or NEED_KEY */
Simon Kelley9a31b682015-12-15 10:20:39 +00001985 return rc;
Simon Kelleya6004d72017-10-25 17:48:19 +01001986 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001987
Simon Kelleya6004d72017-10-25 17:48:19 +01001988 /* Zone is insecure, don't need to validate RRset */
1989 if (rc == STAT_SECURE)
Simon Kelley9a31b682015-12-15 10:20:39 +00001990 {
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001991 unsigned long sig_ttl;
Simon Kelleya6004d72017-10-25 17:48:19 +01001992 rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
Simon Kelleyae7a3b92019-09-03 14:40:47 +01001993 rrcnt, name, keyname, &wildname, NULL, 0, 0, 0, &sig_ttl);
Simon Kelleya6004d72017-10-25 17:48:19 +01001994
1995 if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
1996 {
1997 if (class)
1998 *class = class1; /* Class for DS or DNSKEY */
1999 return rc;
2000 }
2001
Simon Kelley9a31b682015-12-15 10:20:39 +00002002 /* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
Simon Kelleya6004d72017-10-25 17:48:19 +01002003
2004 /* Note that RR is validated */
Simon Kelleyae7a3b92019-09-03 14:40:47 +01002005 daemon->rr_status[i] = sig_ttl;
Simon Kelleya6004d72017-10-25 17:48:19 +01002006
Simon Kelley9a31b682015-12-15 10:20:39 +00002007 /* Note if we've validated either the answer to the question
2008 or the target of a CNAME. Any not noted will need NSEC or
2009 to be in unsigned space. */
Simon Kelley9a31b682015-12-15 10:20:39 +00002010 for (j = 0; j <targetidx; j++)
2011 if ((p2 = targets[j]))
2012 {
Simon Kelleya6004d72017-10-25 17:48:19 +01002013 int rc1;
2014 if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley9a31b682015-12-15 10:20:39 +00002015 return STAT_BOGUS; /* bad packet */
2016
Simon Kelleya6004d72017-10-25 17:48:19 +01002017 if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
Simon Kelley9a31b682015-12-15 10:20:39 +00002018 targets[j] = NULL;
2019 }
Simon Kelleya6004d72017-10-25 17:48:19 +01002020
2021 /* An attacker replay a wildcard answer with a different
2022 answer and overlay a genuine RR. To prove this
2023 hasn't happened, the answer must prove that
2024 the genuine record doesn't exist. Check that here.
2025 Note that we may not yet have validated the NSEC/NSEC3 RRsets.
2026 That's not a problem since if the RRsets later fail
2027 we'll return BOGUS then. */
2028 if (rc == STAT_SECURE_WILDCARD &&
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01002029 !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL, NULL))
Simon Kelleyb40f26c2015-12-17 11:57:26 +00002030 return STAT_BOGUS;
Simon Kelleya6004d72017-10-25 17:48:19 +01002031
2032 rc = STAT_SECURE;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002033 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00002034 }
2035 }
2036
Simon Kelleya6004d72017-10-25 17:48:19 +01002037 if (rc == STAT_INSECURE)
2038 secure = STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02002039 }
2040
Simon Kelley9a31b682015-12-15 10:20:39 +00002041 /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
Simon Kelley7f008432018-04-15 20:01:49 +01002042 if (secure == STAT_SECURE)
Simon Kelley4e72fec2018-04-11 22:49:31 +01002043 for (j = 0; j <targetidx; j++)
2044 if ((p2 = targets[j]))
2045 {
2046 if (neganswer)
2047 *neganswer = 1;
2048
2049 if (!extract_name(header, plen, &p2, name, 1, 10))
2050 return STAT_BOGUS; /* bad packet */
2051
2052 /* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
2053
2054 /* For anything other than a DS record, this situation is OK if either
2055 the answer is in an unsigned zone, or there's a NSEC records. */
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01002056 if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons, nsec_ttl))
Simon Kelley4e72fec2018-04-11 22:49:31 +01002057 {
2058 /* Empty DS without NSECS */
2059 if (qtype == T_DS)
2060 return STAT_BOGUS;
2061
2062 if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
2063 {
2064 if (class)
2065 *class = qclass; /* Class for NEED_DS or NEED_KEY */
2066 return rc;
2067 }
2068
2069 return STAT_BOGUS; /* signed zone, no NSECs */
2070 }
2071 }
Simon Kelley9a31b682015-12-15 10:20:39 +00002072
Simon Kelleya6004d72017-10-25 17:48:19 +01002073 return secure;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002074}
2075
2076
Giovanni Bajo3471f182012-04-25 17:49:16 +02002077/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002078int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02002079{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002080 if (alg == 1)
2081 {
2082 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
2083 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002084 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002085 }
2086 else
2087 {
Simon Kelley1633e302014-02-10 16:42:46 +00002088 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002089 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002090
Simon Kelley0fc2f312014-01-08 10:26:58 +00002091 for (i = 0; i < keylen; ++i)
2092 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002093
Simon Kelley0fc2f312014-01-08 10:26:58 +00002094 ac += (ac >> 16) & 0xffff;
2095 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002096 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002097}
2098
Simon Kelley33702ab2015-12-28 23:17:15 +00002099size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
Simon Kelleye1791f32018-10-06 23:23:23 +01002100 int type, int edns_pktsz)
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002101{
2102 unsigned char *p;
Simon Kelleya77cec82015-05-08 16:25:38 +01002103 size_t ret;
Giovanni Bajo0304d282012-05-02 03:29:52 +02002104
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002105 header->qdcount = htons(1);
2106 header->ancount = htons(0);
2107 header->nscount = htons(0);
2108 header->arcount = htons(0);
2109
2110 header->hb3 = HB3_RD;
2111 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002112 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2113 this allows it to select auth servers when one is returning bad data. */
2114 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002115
2116 /* ID filled in later */
2117
2118 p = (unsigned char *)(header+1);
2119
Simon Kelley0549c732017-09-25 18:17:11 +01002120 p = do_rfc1035_name(p, name, NULL);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002121 *p++ = 0;
2122 PUTSHORT(type, p);
2123 PUTSHORT(class, p);
2124
Simon Kelleya77cec82015-05-08 16:25:38 +01002125 ret = add_do_bit(header, p - (unsigned char *)header, end);
2126
Simon Kelley5bb88f02015-12-21 16:23:47 +00002127 if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
Simon Kelleya77cec82015-05-08 16:25:38 +01002128 PUTSHORT(edns_pktsz, p);
2129
2130 return ret;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002131}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002132
Simon Kelley0fc2f312014-01-08 10:26:58 +00002133#endif /* HAVE_DNSSEC */