blob: 44d626bc2f840b4eb075c2ca327bf922a13010ae [file] [log] [blame]
Giovanni Bajo8d41ebd2012-05-05 00:48:12 +02001/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
Simon Kelley0fc2f312014-01-08 10:26:58 +00002 and Copyright (c) 2012-2014 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
Simon Kelley86bec2d2014-01-13 21:31:20 +000022#include <nettle/rsa.h>
23#include <nettle/dsa.h>
Simon Kelleyc152dc82014-02-19 18:14:33 +000024#ifndef NO_NETTLE_ECC
25# include <nettle/ecdsa.h>
26# include <nettle/ecc-curve.h>
27#endif
Simon Kelley86bec2d2014-01-13 21:31:20 +000028#include <nettle/nettle-meta.h>
29#include <gmp.h>
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000030
Giovanni Bajoe292e932012-04-22 14:32:02 +020031#define SERIAL_UNDEF -100
32#define SERIAL_EQ 0
33#define SERIAL_LT -1
34#define SERIAL_GT 1
35
Simon Kelley86bec2d2014-01-13 21:31:20 +000036/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
37static char *ds_digest_name(int digest)
38{
39 switch (digest)
40 {
41 case 1: return "sha1";
42 case 2: return "sha256";
43 case 3: return "gosthash94";
44 case 4: return "sha384";
45 default: return NULL;
46 }
47}
48
49/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
50static char *algo_digest_name(int algo)
51{
52 switch (algo)
53 {
54 case 1: return "md5";
55 case 3: return "sha1";
56 case 5: return "sha1";
57 case 6: return "sha1";
58 case 7: return "sha1";
59 case 8: return "sha256";
60 case 10: return "sha512";
61 case 12: return "gosthash94";
62 case 13: return "sha256";
63 case 14: return "sha384";
64 default: return NULL;
65 }
66}
67
68/* Find pointer to correct hash function in nettle library */
69static const struct nettle_hash *hash_find(char *name)
70{
71 int i;
72
73 if (!name)
74 return NULL;
75
76 for (i = 0; nettle_hashes[i]; i++)
77 {
78 if (strcmp(nettle_hashes[i]->name, name) == 0)
79 return nettle_hashes[i];
80 }
81
82 return NULL;
83}
84
85/* expand ctx and digest memory allocations if necessary and init hash function */
86static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
87{
88 static void *ctx = NULL;
89 static unsigned char *digest = NULL;
90 static unsigned int ctx_sz = 0;
91 static unsigned int digest_sz = 0;
92
93 void *new;
94
95 if (ctx_sz < hash->context_size)
96 {
97 if (!(new = whine_malloc(hash->context_size)))
98 return 0;
99 if (ctx)
100 free(ctx);
101 ctx = new;
102 ctx_sz = hash->context_size;
103 }
104
105 if (digest_sz < hash->digest_size)
106 {
107 if (!(new = whine_malloc(hash->digest_size)))
108 return 0;
109 if (digest)
110 free(digest);
111 digest = new;
112 digest_sz = hash->digest_size;
113 }
114
115 *ctxp = ctx;
116 *digestp = digest;
117
118 hash->init(ctx);
119
120 return 1;
121}
122
123static int rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
124 unsigned char *digest, int algo)
125{
126 unsigned char *p;
127 size_t exp_len;
128
129 static struct rsa_public_key *key = NULL;
130 static mpz_t sig_mpz;
131
132 if (key == NULL)
133 {
134 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
135 return 0;
136
137 nettle_rsa_public_key_init(key);
138 mpz_init(sig_mpz);
139 }
140
141 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
142 return 0;
143
144 key_len--;
145 if ((exp_len = *p++) == 0)
146 {
147 GETSHORT(exp_len, p);
148 key_len -= 2;
149 }
150
151 if (exp_len >= key_len)
152 return 0;
153
154 key->size = key_len - exp_len;
155 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
156 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
157
158 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
159
160 switch (algo)
161 {
162 case 1:
163 return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
164 case 5: case 7:
165 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
166 case 8:
167 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
168 case 10:
169 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
170 }
171
172 return 0;
173}
174
175static int dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
176 unsigned char *digest, int algo)
177{
178 unsigned char *p;
179 unsigned int t;
180
181 static struct dsa_public_key *key = NULL;
182 static struct dsa_signature *sig_struct;
183
184 if (key == NULL)
185 {
186 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
187 !(key = whine_malloc(sizeof(struct dsa_public_key))))
188 return 0;
189
190 nettle_dsa_public_key_init(key);
191 nettle_dsa_signature_init(sig_struct);
192 }
193
194 if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
195 return 0;
196
197 t = *p++;
198
199 if (key_len < (213 + (t * 24)))
200 return 0;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000201
Simon Kelley86bec2d2014-01-13 21:31:20 +0000202 mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
203 mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
204 mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
205 mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
206
207 mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
208 mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
209
210 (void)algo;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000211
Simon Kelley86bec2d2014-01-13 21:31:20 +0000212 return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
213}
214
Simon Kelleyc152dc82014-02-19 18:14:33 +0000215#ifndef NO_NETTLE_ECC
216static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
217 unsigned char *sig, size_t sig_len,
Simon Kelleyebe95a82014-02-13 14:56:10 +0000218 unsigned char *digest, size_t digest_len, int algo)
219{
220 unsigned char *p;
221 unsigned int t;
222 struct ecc_point *key;
223
224 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
225 static mpz_t x, y;
226 static struct dsa_signature *sig_struct;
227
228 if (!sig_struct)
229 {
230 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
231 return 0;
232
233 nettle_dsa_signature_init(sig_struct);
234 mpz_init(x);
235 mpz_init(y);
236 }
237
238 switch (algo)
239 {
240 case 13:
241 if (!key_256)
242 {
243 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
244 return 0;
245
246 nettle_ecc_point_init(key_256, &nettle_secp_256r1);
247 }
248
249 key = key_256;
250 t = 32;
251 break;
252
253 case 14:
254 if (!key_384)
255 {
256 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
257 return 0;
258
259 nettle_ecc_point_init(key_384, &nettle_secp_384r1);
260 }
261
262 key = key_384;
263 t = 48;
264 break;
265
266 default:
267 return 0;
268 }
269
270 if (sig_len != 2*t || key_len != 2*t ||
271 (p = blockdata_retrieve(key_data, key_len, NULL)))
272 return 0;
273
274 mpz_import(x, t , 1, 1, 0, 0, p);
275 mpz_import(y, t , 1, 1, 0, 0, p + t);
276
277 if (!ecc_point_set(key, x, y))
278 return 0;
279
280 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
281 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
282
283 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
284}
Simon Kelleyc152dc82014-02-19 18:14:33 +0000285#endif
286
Simon Kelley86bec2d2014-01-13 21:31:20 +0000287static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
Simon Kelleyebe95a82014-02-13 14:56:10 +0000288 unsigned char *digest, size_t digest_len, int algo)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000289{
Simon Kelley7b1eae42014-02-20 13:43:28 +0000290 (void)digest_len;
291
Simon Kelley86bec2d2014-01-13 21:31:20 +0000292 switch (algo)
293 {
294 case 1: case 5: case 7: case 8: case 10:
295 return rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
296
297 case 3: case 6:
298 return dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
Simon Kelleyc152dc82014-02-19 18:14:33 +0000299
300#ifndef NO_NETTLE_ECC
Simon Kelleyebe95a82014-02-13 14:56:10 +0000301 case 13: case 14:
302 return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
Simon Kelleyc152dc82014-02-19 18:14:33 +0000303#endif
304 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000305
306 return 0;
307}
308
Simon Kelley0fc2f312014-01-08 10:26:58 +0000309/* Convert from presentation format to wire format, in place.
310 Also map UC -> LC.
311 Note that using extract_name to get presentation format
312 then calling to_wire() removes compression and maps case,
313 thus generating names in canonical form.
314 Calling to_wire followed by from_wire is almost an identity,
315 except that the UC remains mapped to LC.
316*/
317static int to_wire(char *name)
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200318{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000319 unsigned char *l, *p, term;
320 int len;
321
322 for (l = (unsigned char*)name; *l != 0; l = p)
323 {
324 for (p = l; *p != '.' && *p != 0; p++)
325 if (*p >= 'A' && *p <= 'Z')
326 *p = *p - 'A' + 'a';
327
328 term = *p;
329
330 if ((len = p - l) != 0)
331 memmove(l+1, l, len);
332 *l = len;
333
334 p++;
335
336 if (term == 0)
337 *p = 0;
338 }
339
340 return l + 1 - (unsigned char *)name;
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200341}
342
Simon Kelley0fc2f312014-01-08 10:26:58 +0000343/* Note: no compression allowed in input. */
344static void from_wire(char *name)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200345{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000346 unsigned char *l;
347 int len;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200348
Simon Kelley0fc2f312014-01-08 10:26:58 +0000349 for (l = (unsigned char *)name; *l != 0; l += len+1)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200350 {
Simon Kelley0fc2f312014-01-08 10:26:58 +0000351 len = *l;
352 memmove(l, l+1, len);
353 l[len] = '.';
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200354 }
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200355
Simon Kelleye3f14552014-03-01 17:58:28 +0000356 if ((char *)l != name)
Simon Kelleybd9b3cf2014-03-01 16:12:28 +0000357 *(l-1) = 0;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200358}
359
Simon Kelley5ada8882014-01-09 22:25:03 +0000360/* Input in presentation format */
361static int count_labels(char *name)
362{
363 int i;
364
365 if (*name == 0)
366 return 0;
367
368 for (i = 0; *name; name++)
369 if (*name == '.')
370 i++;
371
372 return i+1;
373}
374
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000375/* Implement RFC1982 wrapped compare for 32-bit numbers */
376static int serial_compare_32(unsigned long s1, unsigned long s2)
Giovanni Bajo0852d762012-04-28 03:49:24 +0200377{
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000378 if (s1 == s2)
379 return SERIAL_EQ;
Giovanni Bajo0852d762012-04-28 03:49:24 +0200380
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000381 if ((s1 < s2 && (s2 - s1) < (1UL<<31)) ||
382 (s1 > s2 && (s1 - s2) > (1UL<<31)))
383 return SERIAL_LT;
384 if ((s1 < s2 && (s2 - s1) > (1UL<<31)) ||
385 (s1 > s2 && (s1 - s2) < (1UL<<31)))
386 return SERIAL_GT;
387 return SERIAL_UNDEF;
388}
Giovanni Bajo0852d762012-04-28 03:49:24 +0200389
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000390/* Check whether today/now is between date_start and date_end */
391static int check_date_range(unsigned long date_start, unsigned long date_end)
392{
Simon Kelleye98bd522014-03-28 20:41:23 +0000393 unsigned long curtime;
394
395 /* Checking timestamps may be temporarily disabled */
396 if (option_bool(OPT_DNSSEC_TIME))
397 return 1;
398
399 curtime = time(0);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000400
401 /* We must explicitly check against wanted values, because of SERIAL_UNDEF */
402 return serial_compare_32(curtime, date_start) == SERIAL_GT
403 && serial_compare_32(curtime, date_end) == SERIAL_LT;
404}
405
406static u16 *get_desc(int type)
407{
408 /* List of RRtypes which include domains in the data.
409 0 -> domain
410 integer -> no of plain bytes
411 -1 -> end
412
413 zero is not a valid RRtype, so the final entry is returned for
414 anything which needs no mangling.
415 */
416
417 static u16 rr_desc[] =
418 {
419 T_NS, 0, -1,
420 T_MD, 0, -1,
421 T_MF, 0, -1,
422 T_CNAME, 0, -1,
423 T_SOA, 0, 0, -1,
424 T_MB, 0, -1,
425 T_MG, 0, -1,
426 T_MR, 0, -1,
427 T_PTR, 0, -1,
428 T_MINFO, 0, 0, -1,
429 T_MX, 2, 0, -1,
430 T_RP, 0, 0, -1,
431 T_AFSDB, 2, 0, -1,
432 T_RT, 2, 0, -1,
433 T_SIG, 18, 0, -1,
434 T_PX, 2, 0, 0, -1,
435 T_NXT, 0, -1,
436 T_KX, 2, 0, -1,
437 T_SRV, 6, 0, -1,
438 T_DNAME, 0, -1,
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000439 0, -1 /* wildcard/catchall */
440 };
441
442 u16 *p = rr_desc;
443
444 while (*p != type && *p != 0)
445 while (*p++ != (u16)-1);
446
447 return p+1;
448}
449
450/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
451 data, pointed to by *p, should be used raw. */
452static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff,
453 unsigned char **p, u16 **desc)
454{
455 int d = **desc;
456
457 (*desc)++;
458
459 /* No more data needs mangling */
460 if (d == (u16)-1)
Giovanni Bajof119ed32012-05-02 00:31:55 +0200461 return 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000462
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000463 if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
464 /* domain-name, canonicalise */
465 return to_wire(buff);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000466 else
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000467 {
468 /* plain data preceding a domain-name, don't run off the end of the data */
469 if ((end - *p) < d)
470 d = end - *p;
471
472 if (d != 0)
473 {
474 memcpy(buff, *p, d);
475 *p += d;
476 }
477
478 return d;
479 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000480}
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000481
Simon Kelley613ad152014-02-25 23:02:28 +0000482static int expand_workspace(unsigned char ***wkspc, int *sz, int new)
483{
484 unsigned char **p;
485 int new_sz = *sz;
486
487 if (new_sz > new)
488 return 1;
489
490 if (new >= 100)
491 return 0;
492
493 new_sz += 5;
494
495 if (!(p = whine_malloc((new_sz) * sizeof(unsigned char **))))
496 return 0;
497
498 if (*wkspc)
499 {
500 memcpy(p, *wkspc, *sz * sizeof(unsigned char **));
501 free(*wkspc);
502 }
503
504 *wkspc = p;
505 *sz = new_sz;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000506
507 return 1;
Simon Kelley613ad152014-02-25 23:02:28 +0000508}
509
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000510/* Bubble sort the RRset into the canonical order.
511 Note that the byte-streams from two RRs may get unsynced: consider
512 RRs which have two domain-names at the start and then other data.
513 The domain-names may have different lengths in each RR, but sort equal
514
515 ------------
516 |abcde|fghi|
517 ------------
518 |abcd|efghi|
519 ------------
520
521 leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
522*/
523
524static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
525 unsigned char **rrset, char *buff1, char *buff2)
526{
527 int swap, quit, i;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000528
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000529 do
530 {
531 for (swap = 0, i = 0; i < rrsetidx-1; i++)
532 {
533 int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
534 u16 *dp1, *dp2;
535 unsigned char *end1, *end2;
Simon Kelley5107ace2014-02-23 10:48:32 +0000536 /* Note that these have been determined to be OK previously,
537 so we don't need to check for NULL return here. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000538 unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
539 unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
540
541 p1 += 8; /* skip class, type, ttl */
542 GETSHORT(rdlen1, p1);
543 end1 = p1 + rdlen1;
544
545 p2 += 8; /* skip class, type, ttl */
546 GETSHORT(rdlen2, p2);
547 end2 = p2 + rdlen2;
548
549 dp1 = dp2 = rr_desc;
550
Simon Kelley1486a9c2014-01-10 11:39:14 +0000551 for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000552 {
Simon Kelley1486a9c2014-01-10 11:39:14 +0000553 if (left1 != 0)
554 memmove(buff1, buff1 + len1 - left1, left1);
555
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000556 if ((len1 = get_rdata(header, plen, end1, buff1 + left1, &p1, &dp1)) == 0)
557 {
558 quit = 1;
559 len1 = end1 - p1;
560 memcpy(buff1 + left1, p1, len1);
561 }
562 len1 += left1;
563
Simon Kelley1486a9c2014-01-10 11:39:14 +0000564 if (left2 != 0)
565 memmove(buff2, buff2 + len2 - left2, left2);
566
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000567 if ((len2 = get_rdata(header, plen, end2, buff2 + left2, &p2, &dp2)) == 0)
568 {
569 quit = 1;
570 len2 = end2 - p2;
571 memcpy(buff2 + left2, p2, len2);
572 }
573 len2 += left2;
574
575 if (len1 > len2)
Simon Kelley1486a9c2014-01-10 11:39:14 +0000576 left1 = len1 - len2, left2 = 0, len = len2;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000577 else
Simon Kelley1486a9c2014-01-10 11:39:14 +0000578 left2 = len2 - len1, left1 = 0, len = len1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000579
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000580 rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000581
Simon Kelley4619d942014-01-16 19:53:06 +0000582 if (rc > 0 || (rc == 0 && quit && len1 > len2))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000583 {
584 unsigned char *tmp = rrset[i+1];
585 rrset[i+1] = rrset[i];
586 rrset[i] = tmp;
587 swap = quit = 1;
588 }
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000589 else if (rc < 0)
590 quit = 1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000591 }
592 }
593 } while (swap);
594}
595
596/* Validate a single RRset (class, type, name) in the supplied DNS reply
597 Return code:
598 STAT_SECURE if it validates.
Simon Kelley5107ace2014-02-23 10:48:32 +0000599 STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000600 STAT_NO_SIG no RRsigs found.
Simon Kelley87070192014-03-01 20:48:24 +0000601 STAT_INSECURE RRset empty.
602 STAT_BOGUS signature is wrong, bad packet.
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000603 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
604
605 if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
606 otherwise find the key in the cache.
Simon Kelley5107ace2014-02-23 10:48:32 +0000607
608 name is unchanged on exit. keyname is used as workspace and trashed.
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000609*/
610static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class,
Simon Kelleye7829ae2014-01-22 22:21:51 +0000611 int type, char *name, char *keyname, struct blockdata *key, int keylen, int algo_in, int keytag_in)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000612{
613 static unsigned char **rrset = NULL, **sigs = NULL;
614 static int rrset_sz = 0, sig_sz = 0;
615
616 unsigned char *p;
Simon Kelley5ada8882014-01-09 22:25:03 +0000617 int rrsetidx, sigidx, res, rdlen, j, name_labels;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000618 struct crec *crecp = NULL;
619 int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
620 u16 *rr_desc = get_desc(type);
621
622 if (!(p = skip_questions(header, plen)))
Simon Kelley87070192014-03-01 20:48:24 +0000623 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000624
Simon Kelley5ada8882014-01-09 22:25:03 +0000625 name_labels = count_labels(name); /* For 4035 5.3.2 check */
626
627 /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000628 for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
629 j != 0; j--)
630 {
631 unsigned char *pstart, *pdata;
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000632 int stype, sclass;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000633
634 pstart = p;
635
636 if (!(res = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +0000637 return STAT_BOGUS; /* bad packet */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000638
639 GETSHORT(stype, p);
640 GETSHORT(sclass, p);
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000641 p += 4; /* TTL */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000642
643 pdata = p;
644
645 GETSHORT(rdlen, p);
646
Simon Kelleye7829ae2014-01-22 22:21:51 +0000647 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000648 return STAT_BOGUS;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000649
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000650 if (res == 1 && sclass == class)
651 {
652 if (stype == type)
653 {
Simon Kelley613ad152014-02-25 23:02:28 +0000654 if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
Simon Kelley87070192014-03-01 20:48:24 +0000655 return STAT_BOGUS;
Simon Kelley613ad152014-02-25 23:02:28 +0000656
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000657 rrset[rrsetidx++] = pstart;
658 }
659
660 if (stype == T_RRSIG)
661 {
Simon Kelley613ad152014-02-25 23:02:28 +0000662 if (rdlen < 18)
Simon Kelley87070192014-03-01 20:48:24 +0000663 return STAT_BOGUS; /* bad packet */
Simon Kelley613ad152014-02-25 23:02:28 +0000664
665 GETSHORT(type_covered, p);
666
667 if (type_covered == type)
668 {
669 if (!expand_workspace(&sigs, &sig_sz, sigidx))
Simon Kelley87070192014-03-01 20:48:24 +0000670 return STAT_BOGUS;
Simon Kelley613ad152014-02-25 23:02:28 +0000671
672 sigs[sigidx++] = pdata;
673 }
674
675 p = pdata + 2; /* restore for ADD_RDLEN */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000676 }
677 }
Simon Kelley613ad152014-02-25 23:02:28 +0000678
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000679 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000680 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000681 }
682
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000683 /* RRset empty */
684 if (rrsetidx == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000685 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000686
687 /* no RRSIGs */
688 if (sigidx == 0)
689 return STAT_NO_SIG;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000690
691 /* Sort RRset records into canonical order.
Simon Kelleyd3873802014-02-23 16:20:46 +0000692 Note that at this point keyname and daemon->workspacename buffs are
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000693 unused, and used as workspace by the sort. */
Simon Kelleyd3873802014-02-23 16:20:46 +0000694 sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000695
696 /* Now try all the sigs to try and find one which validates */
697 for (j = 0; j <sigidx; j++)
698 {
Simon Kelleyd3873802014-02-23 16:20:46 +0000699 unsigned char *psav, *sig, *digest;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000700 int i, wire_len, sig_len;
701 const struct nettle_hash *hash;
702 void *ctx;
Simon Kelleyd3873802014-02-23 16:20:46 +0000703 char *name_start;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000704 u32 nsigttl;
705
706 p = sigs[j];
Simon Kelley5ada8882014-01-09 22:25:03 +0000707 GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000708 psav = p;
709
Simon Kelley5ada8882014-01-09 22:25:03 +0000710 p += 2; /* type_covered - already checked */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000711 algo = *p++;
712 labels = *p++;
713 GETLONG(orig_ttl, p);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000714 GETLONG(sig_expiration, p);
715 GETLONG(sig_inception, p);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000716 GETSHORT(key_tag, p);
717
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000718 if (!extract_name(header, plen, &p, keyname, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +0000719 return STAT_BOGUS;
Simon Kelleyd3873802014-02-23 16:20:46 +0000720
721 /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
722 the name of the zone containing the RRset. We can't tell that
723 for certain, but we can check that the RRset name is equal to
724 or encloses the signers name, which should be enough to stop
725 an attacker using signatures made with the key of an unrelated
726 zone he controls. Note that the root key is always allowed. */
727 if (*keyname != 0)
728 {
729 int failed = 0;
730
731 for (name_start = name; !hostname_isequal(name_start, keyname); )
732 if ((name_start = strchr(name_start, '.')))
733 name_start++; /* chop a label off and try again */
734 else
735 {
736 failed = 1;
737 break;
738 }
739
740 /* Bad sig, try another */
741 if (failed)
742 continue;
743 }
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000744
Simon Kelleyd3873802014-02-23 16:20:46 +0000745 /* Other 5.3.1 checks */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000746 if (!check_date_range(sig_inception, sig_expiration) ||
747 labels > name_labels ||
748 !(hash = hash_find(algo_digest_name(algo))) ||
749 !hash_init(hash, &ctx, &digest))
750 continue;
751
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000752 /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
753 if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
754 return STAT_NEED_KEY;
755
Simon Kelley86bec2d2014-01-13 21:31:20 +0000756 sig = p;
757 sig_len = rdlen - (p - psav);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000758
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000759 nsigttl = htonl(orig_ttl);
760
Simon Kelley86bec2d2014-01-13 21:31:20 +0000761 hash->update(ctx, 18, psav);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000762 wire_len = to_wire(keyname);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000763 hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000764 from_wire(keyname);
765
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000766 for (i = 0; i < rrsetidx; ++i)
767 {
768 int seg;
769 unsigned char *end, *cp;
770 u16 len, *dp;
Simon Kelleyd3873802014-02-23 16:20:46 +0000771
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000772 p = rrset[i];
773 if (!extract_name(header, plen, &p, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +0000774 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000775
Simon Kelleyd3873802014-02-23 16:20:46 +0000776 name_start = name;
777
Simon Kelley5ada8882014-01-09 22:25:03 +0000778 /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
779 if (labels < name_labels)
780 {
781 int k;
782 for (k = name_labels - labels; k != 0; k--)
783 while (*name_start != '.' && *name_start != 0)
784 name_start++;
785 name_start--;
786 *name_start = '*';
787 }
788
789 wire_len = to_wire(name_start);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000790 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
791 hash->update(ctx, 4, p); /* class and type */
792 hash->update(ctx, 4, (unsigned char *)&nsigttl);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000793
794 p += 8; /* skip class, type, ttl */
795 GETSHORT(rdlen, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000796 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000797 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000798
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000799 end = p + rdlen;
800
801 /* canonicalise rdata and calculate length of same, use name buffer as workspace */
802 cp = p;
803 dp = rr_desc;
804 for (len = 0; (seg = get_rdata(header, plen, end, name, &cp, &dp)) != 0; len += seg);
805 len += end - cp;
806 len = htons(len);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000807 hash->update(ctx, 2, (unsigned char *)&len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000808
809 /* Now canonicalise again and digest. */
810 cp = p;
811 dp = rr_desc;
812 while ((seg = get_rdata(header, plen, end, name, &cp, &dp)))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000813 hash->update(ctx, seg, (unsigned char *)name);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000814 if (cp != end)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000815 hash->update(ctx, end - cp, cp);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000816 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000817
818 hash->digest(ctx, hash->digest_size, digest);
819
Simon Kelley5ada8882014-01-09 22:25:03 +0000820 /* namebuff used for workspace above, restore to leave unchanged on exit */
821 p = (unsigned char*)(rrset[0]);
822 extract_name(header, plen, &p, name, 1, 0);
823
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000824 if (key)
825 {
826 if (algo_in == algo && keytag_in == key_tag &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000827 verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000828 return STAT_SECURE;
829 }
830 else
831 {
832 /* iterate through all possible keys 4035 5.3.1 */
833 for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000834 if (crecp->addr.key.algo == algo &&
835 crecp->addr.key.keytag == key_tag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000836 crecp->uid == (unsigned int)class &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000837 verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5107ace2014-02-23 10:48:32 +0000838 return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000839 }
840 }
841
842 return STAT_BOGUS;
843}
844
Simon Kelley0fc2f312014-01-08 10:26:58 +0000845/* The DNS packet is expected to contain the answer to a DNSKEY query.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000846 Put all DNSKEYs in the answer which are valid into the cache.
847 return codes:
Simon Kelley87070192014-03-01 20:48:24 +0000848 STAT_INSECURE No DNSKEYs in reply.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000849 STAT_SECURE At least one valid DNSKEY found and in cache.
Simon Kelley0fc2f312014-01-08 10:26:58 +0000850 STAT_BOGUS No DNSKEYs found, which can be validated with DS,
Simon Kelley87070192014-03-01 20:48:24 +0000851 or self-sign for DNSKEY RRset is not valid, bad packet.
Simon Kelley0fc2f312014-01-08 10:26:58 +0000852 STAT_NEED_DS DS records to validate a key not found, name in keyname
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000853*/
854int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
855{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000856 unsigned char *psave, *p = (unsigned char *)(header+1);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000857 struct crec *crecp, *recp1;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000858 int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000859 struct blockdata *key;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000860 struct all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000861
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000862 if (ntohs(header->qdcount) != 1 ||
863 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +0000864 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000865
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000866 GETSHORT(qtype, p);
867 GETSHORT(qclass, p);
868
Simon Kelley87070192014-03-01 20:48:24 +0000869 if (qtype != T_DNSKEY || qclass != class)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000870 return STAT_BOGUS;
Simon Kelley87070192014-03-01 20:48:24 +0000871
872 if (ntohs(header->ancount) == 0)
873 return STAT_INSECURE;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000874
Simon Kelleyb8eac192014-02-27 14:30:03 +0000875 /* See if we have cached a DS record which validates this key */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000876 if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
877 {
878 strcpy(keyname, name);
879 return STAT_NEED_DS;
880 }
Simon Kelleyb8eac192014-02-27 14:30:03 +0000881
882 /* If we've cached that DS provably doesn't exist, result must be INSECURE */
883 if (crecp->flags & F_NEG)
884 return STAT_INSECURE;
885
Simon Kelley0fc2f312014-01-08 10:26:58 +0000886 /* NOTE, we need to find ONE DNSKEY which matches the DS */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000887 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000888 {
889 /* Ensure we have type, class TTL and length */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000890 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +0000891 return STAT_BOGUS; /* bad packet */
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000892
893 GETSHORT(qtype, p);
894 GETSHORT(qclass, p);
895 GETLONG(ttl, p);
896 GETSHORT(rdlen, p);
Simon Kelley6f468102014-01-26 23:39:17 +0000897
Simon Kelley0fc2f312014-01-08 10:26:58 +0000898 if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000899 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000900
Simon Kelley6f468102014-01-26 23:39:17 +0000901 if (qclass != class || qtype != T_DNSKEY || rc == 2)
902 {
903 p += rdlen;
904 continue;
905 }
906
Simon Kelley0fc2f312014-01-08 10:26:58 +0000907 psave = p;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000908
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000909 GETSHORT(flags, p);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000910 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000911 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000912 algo = *p++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000913 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000914 key = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000915
Simon Kelleye7829ae2014-01-22 22:21:51 +0000916 /* key must have zone key flag set */
917 if (flags & 0x100)
918 key = blockdata_alloc((char*)p, rdlen - 4);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000919
920 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000921
Simon Kelley0fc2f312014-01-08 10:26:58 +0000922 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000923 {
924 if (key)
925 blockdata_free(key);
Simon Kelley87070192014-03-01 20:48:24 +0000926 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000927 }
928
Simon Kelleye7829ae2014-01-22 22:21:51 +0000929 /* No zone key flag or malloc failure */
930 if (!key)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000931 continue;
932
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000933 for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000934 {
935 void *ctx;
936 unsigned char *digest, *ds_digest;
937 const struct nettle_hash *hash;
938
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000939 if (recp1->addr.ds.algo == algo &&
940 recp1->addr.ds.keytag == keytag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000941 recp1->uid == (unsigned int)class &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000942 (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
Simon Kelley86bec2d2014-01-13 21:31:20 +0000943 hash_init(hash, &ctx, &digest))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000944
Simon Kelley86bec2d2014-01-13 21:31:20 +0000945 {
946 int wire_len = to_wire(name);
947
948 /* Note that digest may be different between DSs, so
949 we can't move this outside the loop. */
950 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
951 hash->update(ctx, (unsigned int)rdlen, psave);
952 hash->digest(ctx, hash->digest_size, digest);
953
954 from_wire(name);
955
Simon Kelley824202e2014-01-23 20:59:46 +0000956 if (recp1->addr.ds.keylen == (int)hash->digest_size &&
957 (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
958 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
Simon Kelleyf6a2b792014-02-01 14:54:26 +0000959 validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag) == STAT_SECURE)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000960 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000961 valid = 1;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000962 break;
963 }
964 }
965 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000966 blockdata_free(key);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000967 }
968
969 if (valid)
970 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000971 /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000972 cache_start_insert();
973
974 p = skip_questions(header, plen);
975
976 for (j = ntohs(header->ancount); j != 0; j--)
977 {
978 /* Ensure we have type, class TTL and length */
979 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
980 return STAT_INSECURE; /* bad packet */
981
982 GETSHORT(qtype, p);
983 GETSHORT(qclass, p);
984 GETLONG(ttl, p);
985 GETSHORT(rdlen, p);
Simon Kelley8d718cb2014-02-03 16:27:37 +0000986
987 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000988 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000989
Simon Kelley8d718cb2014-02-03 16:27:37 +0000990 if (qclass == class && rc == 1)
Simon Kelleye7829ae2014-01-22 22:21:51 +0000991 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000992 psave = p;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000993
Simon Kelley8d718cb2014-02-03 16:27:37 +0000994 if (qtype == T_DNSKEY)
995 {
996 if (rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000997 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000998
999 GETSHORT(flags, p);
1000 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001001 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001002 algo = *p++;
1003 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
1004
1005 /* Cache needs to known class for DNSSEC stuff */
1006 a.addr.dnssec.class = class;
1007
1008 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
1009 {
1010 if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
1011 blockdata_free(key);
1012 else
1013 {
1014 a.addr.keytag = keytag;
1015 log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
1016
1017 recp1->addr.key.keylen = rdlen - 4;
1018 recp1->addr.key.keydata = key;
1019 recp1->addr.key.algo = algo;
1020 recp1->addr.key.keytag = keytag;
1021 recp1->addr.key.flags = flags;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001022 }
1023 }
1024 }
1025 else if (qtype == T_RRSIG)
1026 {
1027 /* RRSIG, cache if covers DNSKEY RRset */
1028 if (rdlen < 18)
Simon Kelley87070192014-03-01 20:48:24 +00001029 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001030
1031 GETSHORT(type_covered, p);
1032
1033 if (type_covered == T_DNSKEY)
1034 {
1035 a.addr.dnssec.class = class;
1036 a.addr.dnssec.type = type_covered;
1037
1038 algo = *p++;
1039 p += 13; /* labels, orig_ttl, expiration, inception */
1040 GETSHORT(keytag, p);
1041 if ((key = blockdata_alloc((char*)psave, rdlen)))
1042 {
1043 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
1044 blockdata_free(key);
1045 else
1046 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001047 crecp->addr.sig.keydata = key;
1048 crecp->addr.sig.keylen = rdlen;
1049 crecp->addr.sig.keytag = keytag;
1050 crecp->addr.sig.type_covered = type_covered;
1051 crecp->addr.sig.algo = algo;
1052 }
1053 }
1054 }
1055 }
Simon Kelleye7829ae2014-01-22 22:21:51 +00001056
Simon Kelley8d718cb2014-02-03 16:27:37 +00001057 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001058 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001059
Simon Kelleye7829ae2014-01-22 22:21:51 +00001060 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001061 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +00001062 }
1063
Simon Kelley0fc2f312014-01-08 10:26:58 +00001064 /* commit cache insert. */
1065 cache_end_insert();
1066 return STAT_SECURE;
1067 }
1068
1069 log_query(F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
1070 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001071}
Simon Kelley0fc2f312014-01-08 10:26:58 +00001072
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001073/* The DNS packet is expected to contain the answer to a DS query
1074 Put all DSs in the answer which are valid into the cache.
1075 return codes:
Simon Kelley87070192014-03-01 20:48:24 +00001076 STAT_INSECURE no DS in reply or not signed.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001077 STAT_SECURE At least one valid DS found and in cache.
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001078 STAT_NO_DS It's proved there's no DS here.
Simon Kelley87070192014-03-01 20:48:24 +00001079 STAT_BOGUS At least one DS found, which fails validation, bad packet.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001080 STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
1081*/
1082
1083int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
1084{
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001085 unsigned char *p = (unsigned char *)(header+1);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001086 int qtype, qclass, val, i, neganswer;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001087
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001088 if (ntohs(header->qdcount) != 1 ||
Simon Kelleyb8eac192014-02-27 14:30:03 +00001089 !(p = skip_name(p, header, plen, 4)))
Simon Kelley87070192014-03-01 20:48:24 +00001090 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001091
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001092 GETSHORT(qtype, p);
1093 GETSHORT(qclass, p);
1094
Simon Kelleyb47b04c2014-02-25 23:13:28 +00001095 if (qtype != T_DS || qclass != class)
1096 val = STAT_BOGUS;
1097 else
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001098 val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, &neganswer);
1099
1100 if (val == STAT_NO_SIG)
1101 val = STAT_INSECURE;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001102
Simon Kelleyb8eac192014-02-27 14:30:03 +00001103 p = (unsigned char *)(header+1);
1104 extract_name(header, plen, &p, name, 1, 4);
1105 p += 4; /* qtype, qclass */
1106
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001107 if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
Simon Kelley87070192014-03-01 20:48:24 +00001108 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001109
Simon Kelley0fc2f312014-01-08 10:26:58 +00001110 if (val == STAT_BOGUS)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001111 log_query(F_UPSTREAM, name, NULL, "BOGUS DS");
Simon Kelleyb47b04c2014-02-25 23:13:28 +00001112
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001113 if ((val == STAT_SECURE || val == STAT_INSECURE) && neganswer)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001114 {
Simon Kelley14db4212014-03-01 15:35:50 +00001115 int rdlen, flags = F_FORWARD | F_DS | F_NEG;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001116 unsigned long ttl, minttl = ULONG_MAX;
1117 struct all_addr a;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001118
1119 if (RCODE(header) == NXDOMAIN)
1120 flags |= F_NXDOMAIN;
1121
1122 if (val == STAT_SECURE)
1123 flags |= F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001124
1125 for (i = ntohs(header->nscount); i != 0; i--)
1126 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001127 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001128 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001129
1130 GETSHORT(qtype, p);
1131 GETSHORT(qclass, p);
1132 GETLONG(ttl, p);
1133 GETSHORT(rdlen, p);
1134
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001135 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001136 return STAT_BOGUS; /* bad packet */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001137
1138 if (qclass != class || qtype != T_SOA)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001139 {
1140 p += rdlen;
1141 continue;
1142 }
1143
1144 if (ttl < minttl)
1145 minttl = ttl;
1146
1147 /* MNAME */
1148 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001149 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001150 /* RNAME */
1151 if (!(p = skip_name(p, header, plen, 20)))
Simon Kelley87070192014-03-01 20:48:24 +00001152 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001153 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
1154
1155 GETLONG(ttl, p); /* minTTL */
1156 if (ttl < minttl)
1157 minttl = ttl;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001158
1159 break;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001160 }
1161
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001162 if (i != 0)
1163 {
1164 cache_start_insert();
1165
1166 a.addr.dnssec.class = class;
1167 cache_insert(name, &a, now, ttl, flags);
1168
1169 cache_end_insert();
1170 }
Simon Kelleyb8eac192014-02-27 14:30:03 +00001171
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001172 return (val == STAT_SECURE) ? STAT_NO_DS : STAT_INSECURE;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001173 }
1174
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001175 return val;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001176}
1177
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001178/* 4034 6.1 */
1179static int hostname_cmp(const char *a, const char *b)
1180{
Simon Kelleydbf72122014-01-21 14:28:02 +00001181 char *sa, *ea, *ca, *sb, *eb, *cb;
1182 unsigned char ac, bc;
1183
1184 sa = ea = (char *)a + strlen(a);
1185 sb = eb = (char *)b + strlen(b);
1186
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001187 while (1)
1188 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001189 while (sa != a && *(sa-1) != '.')
1190 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001191
Simon Kelleydbf72122014-01-21 14:28:02 +00001192 while (sb != b && *(sb-1) != '.')
1193 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001194
Simon Kelleydbf72122014-01-21 14:28:02 +00001195 ca = sa;
1196 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001197
Simon Kelleydbf72122014-01-21 14:28:02 +00001198 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001199 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001200 if (ca == ea)
1201 {
1202 if (cb == eb)
1203 break;
1204
1205 return -1;
1206 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001207
Simon Kelleydbf72122014-01-21 14:28:02 +00001208 if (cb == eb)
1209 return 1;
1210
1211 ac = (unsigned char) *ca++;
1212 bc = (unsigned char) *cb++;
1213
1214 if (ac >= 'A' && ac <= 'Z')
1215 ac += 'a' - 'A';
1216 if (bc >= 'A' && bc <= 'Z')
1217 bc += 'a' - 'A';
1218
Simon Kelley979cdf92014-01-21 16:26:41 +00001219 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001220 return -1;
1221 else if (ac != bc)
1222 return 1;
1223 }
1224
1225
1226 if (sa == a)
1227 {
1228 if (sb == b)
1229 return 0;
1230
1231 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001232 }
1233
Simon Kelleydbf72122014-01-21 14:28:02 +00001234 if (sb == b)
1235 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001236
Simon Kelleydbf72122014-01-21 14:28:02 +00001237 ea = sa--;
1238 eb = sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001239 }
1240}
1241
Simon Kelley5107ace2014-02-23 10:48:32 +00001242/* Find all the NSEC or NSEC3 records in a reply.
1243 return an array of pointers to them. */
1244static int find_nsec_records(struct dns_header *header, size_t plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd)
1245{
1246 static unsigned char **nsecset = NULL;
1247 static int nsecset_sz = 0;
1248
Simon Kelley87070192014-03-01 20:48:24 +00001249 int type_found = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001250 unsigned char *p = skip_questions(header, plen);
1251 int type, class, rdlen, i, nsecs_found;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001252
Simon Kelley5107ace2014-02-23 10:48:32 +00001253 /* Move to NS section */
1254 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1255 return 0;
1256
1257 for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
1258 {
1259 unsigned char *pstart = p;
1260
1261 if (!(p = skip_name(p, header, plen, 10)))
1262 return 0;
1263
1264 GETSHORT(type, p);
1265 GETSHORT(class, p);
1266 p += 4; /* TTL */
1267 GETSHORT(rdlen, p);
1268
1269 if (class == class_reqd && (type == T_NSEC || type == T_NSEC3))
1270 {
1271 /* No mixed NSECing 'round here, thankyouverymuch */
1272 if (type_found == T_NSEC && type == T_NSEC3)
1273 return 0;
1274 if (type_found == T_NSEC3 && type == T_NSEC)
1275 return 0;
1276
1277 type_found = type;
1278
Simon Kelley613ad152014-02-25 23:02:28 +00001279 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1280 return 0;
1281
Simon Kelley5107ace2014-02-23 10:48:32 +00001282 nsecset[nsecs_found++] = pstart;
1283 }
Simon Kelley613ad152014-02-25 23:02:28 +00001284
Simon Kelley5107ace2014-02-23 10:48:32 +00001285 if (!ADD_RDLEN(header, p, plen, rdlen))
1286 return 0;
1287 }
1288
1289 *nsecsetp = nsecset;
1290 *nsecsetl = nsecs_found;
1291
1292 return type_found;
1293}
1294
Simon Kelley24187532014-02-24 21:46:44 +00001295static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
Simon Kelley5107ace2014-02-23 10:48:32 +00001296 char *workspace1, char *workspace2, char *name, int type)
1297{
1298 int i, rc, rdlen;
1299 unsigned char *p, *psave;
1300 int offset = (type & 0xff) >> 3;
1301 int mask = 0x80 >> (type & 0x07);
1302
1303 /* Find NSEC record that proves name doesn't exist */
1304 for (i = 0; i < nsec_count; i++)
1305 {
1306 p = nsecs[i];
1307 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001308 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001309 p += 8; /* class, type, TTL */
1310 GETSHORT(rdlen, p);
1311 psave = p;
1312 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001313 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001314
1315 rc = hostname_cmp(workspace1, name);
1316
1317 if (rc == 0)
1318 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001319 /* 4035 para 5.4. Last sentence */
1320 if (type == T_NSEC || type == T_RRSIG)
1321 return STAT_SECURE;
1322
Simon Kelley5107ace2014-02-23 10:48:32 +00001323 /* NSEC with the same name as the RR we're testing, check
1324 that the type in question doesn't appear in the type map */
1325 rdlen -= p - psave;
1326 /* rdlen is now length of type map, and p points to it */
1327
1328 while (rdlen >= 2)
1329 {
1330 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001331 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001332
1333 if (p[0] == type >> 8)
1334 {
1335 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001336 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001337 return STAT_BOGUS;
1338
1339 break; /* finshed checking */
1340 }
1341
1342 rdlen -= p[1];
1343 p += p[1];
1344 }
1345
1346 return STAT_SECURE;
1347 }
1348 else if (rc == -1)
1349 {
1350 /* Normal case, name falls between NSEC name and next domain name,
1351 wrap around case, name falls between NSEC name (rc == -1) and end */
1352 if (hostname_cmp(workspace2, name) == 1 || hostname_cmp(workspace1, workspace2) == 1)
1353 return STAT_SECURE;
1354 }
1355 else
1356 {
1357 /* wrap around case, name falls between start and next domain name */
1358 if (hostname_cmp(workspace1, workspace2) == 1 && hostname_cmp(workspace2, name) == 1)
1359 return STAT_SECURE;
1360 }
1361 }
1362
1363 return STAT_BOGUS;
1364}
1365
1366/* return digest length, or zero on error */
1367static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1368 unsigned char *salt, int salt_len, int iterations)
1369{
1370 void *ctx;
1371 unsigned char *digest;
1372 int i;
1373
1374 if (!hash_init(hash, &ctx, &digest))
1375 return 0;
1376
1377 hash->update(ctx, to_wire(in), (unsigned char *)in);
1378 hash->update(ctx, salt_len, salt);
1379 hash->digest(ctx, hash->digest_size, digest);
1380
1381 for(i = 0; i < iterations; i++)
1382 {
1383 hash->update(ctx, hash->digest_size, digest);
1384 hash->update(ctx, salt_len, salt);
1385 hash->digest(ctx, hash->digest_size, digest);
1386 }
1387
1388 from_wire(in);
1389
1390 *out = digest;
1391 return hash->digest_size;
1392}
1393
1394/* Decode base32 to first "." or end of string */
1395static int base32_decode(char *in, unsigned char *out)
1396{
Simon Kelleya857daa2014-02-24 21:01:09 +00001397 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001398 unsigned char *p = out;
1399
Simon Kelleya857daa2014-02-24 21:01:09 +00001400 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001401 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001402 if (c >= '0' && c <= '9')
1403 c -= '0';
1404 else if (c >= 'a' && c <= 'v')
1405 c -= 'a', c += 10;
1406 else if (c >= 'A' && c <= 'V')
1407 c -= 'A', c += 10;
1408 else
1409 return 0;
1410
1411 for (mask = 0x10, i = 0; i < 5; i++)
1412 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001413 if (c & mask)
1414 oc |= 1;
1415 mask = mask >> 1;
1416 if (((++on) & 7) == 0)
1417 *p++ = oc;
1418 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001419 }
1420 }
1421
1422 if ((on & 7) != 0)
1423 return 0;
1424
1425 return p - out;
1426}
1427
Simon Kelley24187532014-02-24 21:46:44 +00001428static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
Simon Kelley5107ace2014-02-23 10:48:32 +00001429 char *workspace1, char *workspace2, char *name, int type)
1430{
Simon Kelleya857daa2014-02-24 21:01:09 +00001431 unsigned char *salt, *p, *digest;
1432 int digest_len, i, iterations, salt_len, hash_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001433 struct nettle_hash const *hash;
1434 char *closest_encloser, *next_closest, *wildcard;
1435
1436 /* Look though the NSEC3 records to find the first one with
1437 an algorithm we support (currently only algo == 1).
1438
1439 Take the algo, iterations, and salt of that record
1440 as the ones we're going to use, and prune any
1441 that don't match. */
1442
1443 for (i = 0; i < nsec_count; i++)
1444 {
1445 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelley87070192014-03-01 20:48:24 +00001446 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001447
1448 p += 10; /* type, class, TTL, rdlen */
1449 algo = *p++;
1450
1451 if (algo == 1)
1452 break; /* known algo */
1453 }
1454
1455 /* No usable NSEC3s */
1456 if (i == nsec_count)
1457 return STAT_BOGUS;
1458
1459 p++; /* flags */
1460 GETSHORT (iterations, p);
1461 salt_len = *p++;
1462 salt = p;
1463 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelley87070192014-03-01 20:48:24 +00001464 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001465
1466 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1467 for (i = 0; i < nsec_count; i++)
1468 {
1469 unsigned char *nsec3p = nsecs[i];
1470 int this_iter;
1471
1472 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1473
1474 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelley87070192014-03-01 20:48:24 +00001475 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001476
1477 p += 10; /* type, class, TTL, rdlen */
1478
1479 if (*p++ != algo)
1480 continue;
1481
1482 p++; /* flags */
1483
Simon Kelleya857daa2014-02-24 21:01:09 +00001484 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001485 if (this_iter != iterations)
1486 continue;
1487
1488 if (salt_len != *p++)
1489 continue;
1490
1491 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelley87070192014-03-01 20:48:24 +00001492 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001493
1494 if (memcmp(p, salt, salt_len) != 0)
1495 continue;
1496
1497 /* All match, put the pointer back */
1498 nsecs[i] = nsec3p;
1499 }
1500
1501 /* Algo is checked as 1 above */
1502 if (!(hash = hash_find("sha1")))
Simon Kelley87070192014-03-01 20:48:24 +00001503 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001504
1505 /* Now, we need the "closest encloser NSEC3" */
1506 closest_encloser = name;
1507 next_closest = NULL;
1508
1509 do
1510 {
1511 if (*closest_encloser == '.')
1512 closest_encloser++;
1513
Simon Kelleya857daa2014-02-24 21:01:09 +00001514 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelley87070192014-03-01 20:48:24 +00001515 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001516
1517 for (i = 0; i < nsec_count; i++)
1518 if ((p = nsecs[i]))
1519 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001520 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001521 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelley87070192014-03-01 20:48:24 +00001522 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001523
Simon Kelleya857daa2014-02-24 21:01:09 +00001524 if (digest_len == base32_len &&
1525 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001526 break; /* Gotit */
1527 }
1528
1529 if (i != nsec_count)
1530 break;
1531
1532 next_closest = closest_encloser;
1533 }
1534 while ((closest_encloser = strchr(closest_encloser, '.')));
1535
1536 /* No usable NSEC3s */
1537 if (i == nsec_count)
1538 return STAT_BOGUS;
1539
1540 if (!next_closest)
1541 {
1542 /* We found an NSEC3 whose hashed name exactly matches the query, so
1543 Now we just need to check the type map. p points to the RR data for the record. */
Simon Kelleya857daa2014-02-24 21:01:09 +00001544 int rdlen;
Simon Kelley5107ace2014-02-23 10:48:32 +00001545 unsigned char *psave;
1546 int offset = (type & 0xff) >> 3;
1547 int mask = 0x80 >> (type & 0x07);
1548
1549 p += 8; /* class, type, TTL */
1550 GETSHORT(rdlen, p);
1551 psave = p;
1552 p += 5 + salt_len; /* algo, flags, iterations, salt_len, salt */
1553 hash_len = *p++;
1554 if (!CHECK_LEN(header, p, plen, hash_len))
Simon Kelley87070192014-03-01 20:48:24 +00001555 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001556 p += hash_len;
1557 rdlen -= p - psave;
1558
1559 while (rdlen >= 2)
1560 {
1561 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001562 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001563
1564 if (p[0] == type >> 8)
1565 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001566 /* Does the NSEC3 say our type exists? */
1567 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001568 return STAT_BOGUS;
1569
1570 break; /* finshed checking */
1571 }
1572
1573 rdlen -= p[1];
1574 p += p[1];
1575 }
1576
1577 return STAT_SECURE;
1578 }
1579
Simon Kelley24187532014-02-24 21:46:44 +00001580 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001581 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelley87070192014-03-01 20:48:24 +00001582 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001583
1584 for (i = 0; i < nsec_count; i++)
1585 if ((p = nsecs[i]))
1586 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001587 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
1588 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelley87070192014-03-01 20:48:24 +00001589 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001590
1591 p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
1592 hash_len = *p++; /* p now points to next hashed name */
1593
1594 if (!CHECK_LEN(header, p, plen, hash_len))
Simon Kelley87070192014-03-01 20:48:24 +00001595 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001596
Simon Kelleya857daa2014-02-24 21:01:09 +00001597 if (digest_len == base32_len && hash_len == base32_len)
Simon Kelley5107ace2014-02-23 10:48:32 +00001598 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001599 if (memcmp(workspace2, digest, digest_len) <= 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001600 {
1601 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1602 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelleya857daa2014-02-24 21:01:09 +00001603 if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001604 return STAT_SECURE;
1605 }
1606 else
1607 {
1608 /* wrap around case, name falls between start and next domain name */
Simon Kelleya857daa2014-02-24 21:01:09 +00001609 if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001610 return STAT_SECURE;
1611 }
1612 }
1613 }
1614
1615 /* Finally, check that there's no seat of wildcard synthesis */
1616 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
1617 return STAT_BOGUS;
1618
1619 wildcard--;
1620 *wildcard = '*';
1621
Simon Kelleya857daa2014-02-24 21:01:09 +00001622 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelley87070192014-03-01 20:48:24 +00001623 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001624
1625 for (i = 0; i < nsec_count; i++)
1626 if ((p = nsecs[i]))
1627 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001628 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001629 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelley87070192014-03-01 20:48:24 +00001630 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001631
1632 p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
1633 hash_len = *p++; /* p now points to next hashed name */
1634
1635 if (!CHECK_LEN(header, p, plen, hash_len))
Simon Kelley87070192014-03-01 20:48:24 +00001636 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001637
Simon Kelleya857daa2014-02-24 21:01:09 +00001638 if (digest_len == base32_len && hash_len == base32_len)
Simon Kelley5107ace2014-02-23 10:48:32 +00001639 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001640 if (memcmp(workspace2, digest, digest_len) <= 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001641 {
1642 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1643 wrap around case, name-hash falls between NSEC3 name-hash and end */
Simon Kelleya857daa2014-02-24 21:01:09 +00001644 if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001645 return STAT_SECURE;
1646 }
1647 else
1648 {
1649 /* wrap around case, name falls between start and next domain name */
Simon Kelleya857daa2014-02-24 21:01:09 +00001650 if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001651 return STAT_SECURE;
1652 }
1653 }
1654 }
1655
1656 return STAT_BOGUS;
1657}
1658
Simon Kelley0fc2f312014-01-08 10:26:58 +00001659/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001660/* Returns are the same as validate_rrset, plus the class if the missing key is in *class */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001661int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001662{
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001663 unsigned char *ans_start, *qname, *p1, *p2, **nsecs;
1664 int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype;
Simon Kelley1fbe4d22014-03-01 20:03:47 +00001665 int i, j, rc, nsec_count, cname_count = CNAME_CHAIN;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001666 int nsec_type = 0, have_answer = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001667
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001668 if (neganswer)
1669 *neganswer = 0;
1670
Simon Kelley87070192014-03-01 20:48:24 +00001671 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001672 return STAT_BOGUS;
1673
Simon Kelley87070192014-03-01 20:48:24 +00001674 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001675 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001676
1677 qname = p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001678
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001679 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001680 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001681
1682 GETSHORT(qtype, p1);
1683 GETSHORT(qclass, p1);
1684 ans_start = p1;
Simon Kelley9d1b22a2014-04-29 13:02:41 +01001685
1686 if (qtype == T_ANY)
1687 have_answer = 1;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001688
1689 /* Can't validate an RRISG query */
1690 if (qtype == T_RRSIG)
1691 return STAT_INSECURE;
1692
1693 cname_loop:
1694 for (j = ntohs(header->ancount); j != 0; j--)
1695 {
1696 /* leave pointer to missing name in qname */
1697
1698 if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001699 return STAT_BOGUS; /* bad packet */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001700
1701 GETSHORT(type2, p1);
1702 GETSHORT(class2, p1);
1703 p1 += 4; /* TTL */
1704 GETSHORT(rdlen2, p1);
1705
1706 if (rc == 1 && qclass == class2)
1707 {
1708 /* Do we have an answer for the question? */
1709 if (type2 == qtype)
1710 {
1711 have_answer = 1;
1712 break;
1713 }
1714 else if (type2 == T_CNAME)
1715 {
1716 qname = p1;
1717
1718 /* looped CNAMES */
1719 if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +00001720 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001721
1722 p1 = ans_start;
1723 goto cname_loop;
1724 }
1725 }
1726
1727 if (!ADD_RDLEN(header, p1, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001728 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001729 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001730
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001731 if (neganswer && !have_answer)
1732 *neganswer = 1;
Simon Kelley05756102014-03-01 18:07:57 +00001733
1734 /* No data, therefore no sigs */
1735 if (ntohs(header->ancount) + ntohs(header->nscount) == 0)
1736 return STAT_NO_SIG;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001737
Simon Kelley0fc2f312014-01-08 10:26:58 +00001738 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001739 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001740 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001741 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001742
1743 GETSHORT(type1, p1);
1744 GETSHORT(class1, p1);
1745 p1 += 4; /* TTL */
1746 GETSHORT(rdlen1, p1);
1747
1748 /* Don't try and validate RRSIGs! */
1749 if (type1 != T_RRSIG)
1750 {
1751 /* Check if we've done this RRset already */
1752 for (p2 = ans_start, j = 0; j < i; j++)
1753 {
1754 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001755 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001756
1757 GETSHORT(type2, p2);
1758 GETSHORT(class2, p2);
1759 p2 += 4; /* TTL */
1760 GETSHORT(rdlen2, p2);
1761
1762 if (type2 == type1 && class2 == class1 && rc == 1)
1763 break; /* Done it before: name, type, class all match. */
1764
1765 if (!ADD_RDLEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001766 return STAT_BOGUS;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001767 }
1768
1769 /* Not done, validate now */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001770 if (j == i)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001771 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001772 int ttl, keytag, algo, digest, type_covered;
1773 unsigned char *psave;
1774 struct all_addr a;
1775 struct blockdata *key;
1776 struct crec *crecp;
1777
Simon Kelley5107ace2014-02-23 10:48:32 +00001778 rc = validate_rrset(now, header, plen, class1, type1, name, keyname, NULL, 0, 0, 0);
1779
1780 if (rc == STAT_SECURE_WILDCARD)
1781 {
1782 /* An attacker replay a wildcard answer with a different
Simon Kelleya857daa2014-02-24 21:01:09 +00001783 answer and overlay a genuine RR. To prove this
Simon Kelley5107ace2014-02-23 10:48:32 +00001784 hasn't happened, the answer must prove that
Simon Kelleya857daa2014-02-24 21:01:09 +00001785 the gennuine record doesn't exist. Check that here. */
Simon Kelley87070192014-03-01 20:48:24 +00001786 if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
1787 return STAT_BOGUS; /* No NSECs or bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001788
1789 if (nsec_type == T_NSEC)
Simon Kelley24187532014-02-24 21:46:44 +00001790 rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
Simon Kelley5107ace2014-02-23 10:48:32 +00001791 else
Simon Kelley24187532014-02-24 21:46:44 +00001792 rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
Simon Kelley5107ace2014-02-23 10:48:32 +00001793
1794 if (rc != STAT_SECURE)
1795 return rc;
1796 }
1797 else if (rc != STAT_SECURE)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001798 {
1799 if (class)
1800 *class = class1; /* Class for DS or DNSKEY */
1801 return rc;
1802 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001803
Simon Kelley8d718cb2014-02-03 16:27:37 +00001804 /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
1805 cache_start_insert();
1806
1807 for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001808 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001809 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001810 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001811
1812 GETSHORT(type2, p2);
1813 GETSHORT(class2, p2);
1814 GETLONG(ttl, p2);
1815 GETSHORT(rdlen2, p2);
1816
1817 if (!CHECK_LEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001818 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001819
Simon Kelley8d718cb2014-02-03 16:27:37 +00001820 if (class2 == class1 && rc == 1)
1821 {
1822 psave = p2;
1823
1824 if (type1 == T_DS && type2 == T_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001825 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001826 if (rdlen2 < 4)
Simon Kelley87070192014-03-01 20:48:24 +00001827 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001828
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001829 GETSHORT(keytag, p2);
1830 algo = *p2++;
1831 digest = *p2++;
1832
1833 /* Cache needs to known class for DNSSEC stuff */
1834 a.addr.dnssec.class = class2;
1835
Simon Kelley8d718cb2014-02-03 16:27:37 +00001836 if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001837 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001838 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
1839 blockdata_free(key);
1840 else
1841 {
1842 a.addr.keytag = keytag;
1843 log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
1844 crecp->addr.ds.digest = digest;
1845 crecp->addr.ds.keydata = key;
1846 crecp->addr.ds.algo = algo;
1847 crecp->addr.ds.keytag = keytag;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001848 crecp->addr.ds.keylen = rdlen2 - 4;
1849 }
1850 }
1851 }
1852 else if (type2 == T_RRSIG)
1853 {
1854 if (rdlen2 < 18)
Simon Kelley87070192014-03-01 20:48:24 +00001855 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001856
Simon Kelley8d718cb2014-02-03 16:27:37 +00001857 GETSHORT(type_covered, p2);
1858
1859 if (type_covered == type1 &&
1860 (type_covered == T_A || type_covered == T_AAAA ||
1861 type_covered == T_CNAME || type_covered == T_DS ||
1862 type_covered == T_DNSKEY || type_covered == T_PTR))
1863 {
1864 a.addr.dnssec.type = type_covered;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001865 a.addr.dnssec.class = class1;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001866
1867 algo = *p2++;
1868 p2 += 13; /* labels, orig_ttl, expiration, inception */
1869 GETSHORT(keytag, p2);
1870
1871 if ((key = blockdata_alloc((char*)psave, rdlen2)))
1872 {
1873 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
1874 blockdata_free(key);
1875 else
1876 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001877 crecp->addr.sig.keydata = key;
1878 crecp->addr.sig.keylen = rdlen2;
1879 crecp->addr.sig.keytag = keytag;
1880 crecp->addr.sig.type_covered = type_covered;
1881 crecp->addr.sig.algo = algo;
1882 }
1883 }
1884 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001885 }
1886
Simon Kelley8d718cb2014-02-03 16:27:37 +00001887 p2 = psave;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001888 }
1889
Simon Kelley8d718cb2014-02-03 16:27:37 +00001890 if (!ADD_RDLEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001891 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001892 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001893
1894 cache_end_insert();
Simon Kelley0fc2f312014-01-08 10:26:58 +00001895 }
1896 }
1897
1898 if (!ADD_RDLEN(header, p1, plen, rdlen1))
Simon Kelley87070192014-03-01 20:48:24 +00001899 return STAT_BOGUS;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001900 }
1901
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001902 /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001903 if (have_answer)
1904 return STAT_SECURE;
1905
Simon Kelley5107ace2014-02-23 10:48:32 +00001906 /* NXDOMAIN or NODATA reply, prove that (name, class1, type1) can't exist */
Simon Kelley5107ace2014-02-23 10:48:32 +00001907 /* First marshall the NSEC records, if we've not done it previously */
Simon Kelley87070192014-03-01 20:48:24 +00001908 if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
1909 return STAT_BOGUS; /* No NSECs */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001910
1911 /* Get name of missing answer */
1912 if (!extract_name(header, plen, &qname, name, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +00001913 return STAT_BOGUS;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001914
Simon Kelley5107ace2014-02-23 10:48:32 +00001915 if (nsec_type == T_NSEC)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001916 return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
Simon Kelley5107ace2014-02-23 10:48:32 +00001917 else
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001918 return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
Giovanni Bajoadca3e92012-04-25 17:46:53 +02001919}
1920
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001921/* Chase the CNAME chain in the packet until the first record which _doesn't validate.
1922 Needed for proving answer in unsigned space.
1923 Return STAT_NEED_*
1924 STAT_BOGUS - error
1925 STAT_INSECURE - name of first non-secure record in name
1926*/
1927int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
1928{
1929 unsigned char *p = (unsigned char *)(header+1);
Simon Kelleyc07d30d2014-03-03 14:19:19 +00001930 int type, class, qclass, rdlen, j, rc;
Simon Kelley1fbe4d22014-03-01 20:03:47 +00001931 int cname_count = CNAME_CHAIN;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001932
1933 /* Get question */
1934 if (!extract_name(header, plen, &p, name, 1, 4))
1935 return STAT_BOGUS;
1936
Simon Kelleyc07d30d2014-03-03 14:19:19 +00001937 p +=2; /* type */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001938 GETSHORT(qclass, p);
1939
1940 while (1)
1941 {
1942 for (j = ntohs(header->ancount); j != 0; j--)
1943 {
1944 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
1945 return STAT_BOGUS; /* bad packet */
1946
1947 GETSHORT(type, p);
1948 GETSHORT(class, p);
1949 p += 4; /* TTL */
1950 GETSHORT(rdlen, p);
1951
1952 /* Not target, loop */
1953 if (rc == 2 || qclass != class)
1954 {
1955 if (!ADD_RDLEN(header, p, plen, rdlen))
1956 return STAT_BOGUS;
1957 continue;
1958 }
1959
1960 /* Got to end of CNAME chain. */
1961 if (type != T_CNAME)
1962 return STAT_INSECURE;
1963
1964 /* validate CNAME chain, return if insecure or need more data */
1965 rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, 0, 0, 0);
1966 if (rc != STAT_SECURE)
1967 {
1968 if (rc == STAT_NO_SIG)
1969 rc = STAT_INSECURE;
1970 return rc;
1971 }
1972
1973 /* Loop down CNAME chain/ */
1974 if (!cname_count-- ||
1975 !extract_name(header, plen, &p, name, 1, 0) ||
1976 !(p = skip_questions(header, plen)))
1977 return STAT_BOGUS;
1978
1979 break;
1980 }
1981
1982 /* End of CNAME chain */
1983 return STAT_INSECURE;
1984 }
1985}
1986
1987
Giovanni Bajo3471f182012-04-25 17:49:16 +02001988/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001989int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02001990{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001991 if (alg == 1)
1992 {
1993 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
1994 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001995 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001996 }
1997 else
1998 {
Simon Kelley1633e302014-02-10 16:42:46 +00001999 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002000 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002001
Simon Kelley0fc2f312014-01-08 10:26:58 +00002002 for (i = 0; i < keylen; ++i)
2003 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002004
Simon Kelley0fc2f312014-01-08 10:26:58 +00002005 ac += (ac >> 16) & 0xffff;
2006 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002007 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002008}
2009
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002010size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr)
2011{
2012 unsigned char *p;
Simon Kelley610e7822014-02-06 14:45:17 +00002013 char *types = querystr("dnssec-query", type);
Giovanni Bajo0304d282012-05-02 03:29:52 +02002014
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002015 if (addr->sa.sa_family == AF_INET)
2016 log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
2017#ifdef HAVE_IPV6
2018 else
2019 log_query(F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
2020#endif
2021
2022 header->qdcount = htons(1);
2023 header->ancount = htons(0);
2024 header->nscount = htons(0);
2025 header->arcount = htons(0);
2026
2027 header->hb3 = HB3_RD;
2028 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002029 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2030 this allows it to select auth servers when one is returning bad data. */
2031 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002032
2033 /* ID filled in later */
2034
2035 p = (unsigned char *)(header+1);
2036
2037 p = do_rfc1035_name(p, name);
2038 *p++ = 0;
2039 PUTSHORT(type, p);
2040 PUTSHORT(class, p);
2041
2042 return add_do_bit(header, p - (unsigned char *)header, end);
2043}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002044
Simon Kelley613ad152014-02-25 23:02:28 +00002045/* Go through a domain name, find "pointers" and fix them up based on how many bytes
2046 we've chopped out of the packet, or check they don't point into an elided part. */
2047static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
2048{
2049 unsigned char *ansp = *namep;
2050
2051 while(1)
2052 {
2053 unsigned int label_type;
2054
2055 if (!CHECK_LEN(header, ansp, plen, 1))
2056 return 0;
2057
2058 label_type = (*ansp) & 0xc0;
2059
2060 if (label_type == 0xc0)
2061 {
2062 /* pointer for compression. */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002063 unsigned int offset;
2064 int i;
Simon Kelley613ad152014-02-25 23:02:28 +00002065 unsigned char *p;
2066
2067 if (!CHECK_LEN(header, ansp, plen, 2))
2068 return 0;
2069
2070 offset = ((*ansp++) & 0x3f) << 8;
2071 offset |= *ansp++;
2072
2073 p = offset + (unsigned char *)header;
2074
2075 for (i = 0; i < rr_count; i++)
2076 if (p < rrs[i])
2077 break;
2078 else
2079 if (i & 1)
2080 offset -= rrs[i] - rrs[i-1];
2081
2082 /* does the pointer end up in an elided RR? */
2083 if (i & 1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002084 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +00002085
2086 /* No, scale the pointer */
2087 if (fixup)
2088 {
2089 ansp -= 2;
2090 *ansp++ = (offset >> 8) | 0xc0;
2091 *ansp++ = offset & 0xff;
2092 }
2093 break;
2094 }
2095 else if (label_type == 0x80)
2096 return 0; /* reserved */
2097 else if (label_type == 0x40)
2098 {
2099 /* Extended label type */
2100 unsigned int count;
2101
2102 if (!CHECK_LEN(header, ansp, plen, 2))
2103 return 0;
2104
2105 if (((*ansp++) & 0x3f) != 1)
2106 return 0; /* we only understand bitstrings */
2107
2108 count = *(ansp++); /* Bits in bitstring */
2109
2110 if (count == 0) /* count == 0 means 256 bits */
2111 ansp += 32;
2112 else
2113 ansp += ((count-1)>>3)+1;
2114 }
2115 else
2116 { /* label type == 0 Bottom six bits is length */
2117 unsigned int len = (*ansp++) & 0x3f;
2118
2119 if (!ADD_RDLEN(header, ansp, plen, len))
2120 return 0;
2121
2122 if (len == 0)
2123 break; /* zero length label marks the end. */
2124 }
2125 }
2126
2127 *namep = ansp;
2128
2129 return 1;
2130}
2131
2132/* Go through RRs and check or fixup the domain names contained within */
2133static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
2134{
2135 int i, type, class, rdlen;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002136 unsigned char *pp;
Simon Kelley613ad152014-02-25 23:02:28 +00002137
Simon Kelley50f86ce2014-04-24 17:59:58 +01002138 for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
Simon Kelley613ad152014-02-25 23:02:28 +00002139 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002140 pp = p;
2141
2142 if (!(p = skip_name(p, header, plen, 10)))
2143 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +00002144
2145 GETSHORT(type, p);
2146 GETSHORT(class, p);
2147 p += 4; /* TTL */
2148 GETSHORT(rdlen, p);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002149
Simon Kelley613ad152014-02-25 23:02:28 +00002150 if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
2151 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002152 /* fixup name of RR */
2153 if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
2154 return 0;
2155
Simon Kelley613ad152014-02-25 23:02:28 +00002156 if (class == C_IN)
2157 {
2158 u16 *d;
Simon Kelley14db4212014-03-01 15:35:50 +00002159
2160 for (pp = p, d = get_desc(type); *d != (u16)-1; d++)
Simon Kelley613ad152014-02-25 23:02:28 +00002161 {
2162 if (*d != 0)
2163 pp += *d;
2164 else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
2165 return 0;
2166 }
2167 }
2168 }
2169
2170 if (!ADD_RDLEN(header, p, plen, rdlen))
2171 return 0;
2172 }
2173
2174 return 1;
2175}
2176
2177
2178size_t filter_rrsigs(struct dns_header *header, size_t plen)
2179{
2180 static unsigned char **rrs;
2181 static int rr_sz = 0;
2182
2183 unsigned char *p = (unsigned char *)(header+1);
Simon Kelley50f86ce2014-04-24 17:59:58 +01002184 int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
Simon Kelley613ad152014-02-25 23:02:28 +00002185
2186 if (ntohs(header->qdcount) != 1 ||
2187 !(p = skip_name(p, header, plen, 4)))
2188 return plen;
2189
2190 GETSHORT(qtype, p);
2191 GETSHORT(qclass, p);
2192
2193 /* First pass, find pointers to start and end of all the records we wish to elide:
2194 records added for DNSSEC, unless explicity queried for */
Simon Kelley50f86ce2014-04-24 17:59:58 +01002195 for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
2196 i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
2197 i++)
Simon Kelley613ad152014-02-25 23:02:28 +00002198 {
2199 unsigned char *pstart = p;
2200 int type, class;
2201
2202 if (!(p = skip_name(p, header, plen, 10)))
2203 return plen;
2204
2205 GETSHORT(type, p);
2206 GETSHORT(class, p);
2207 p += 4; /* TTL */
2208 GETSHORT(rdlen, p);
2209
2210 if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) &&
2211 (type != qtype || class != qclass))
2212 {
2213 if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
2214 return plen;
2215
2216 rrs[rr_found++] = pstart;
2217
2218 if (!ADD_RDLEN(header, p, plen, rdlen))
2219 return plen;
2220
2221 rrs[rr_found++] = p;
2222
2223 if (i < ntohs(header->ancount))
2224 chop_an++;
Simon Kelleye6096e62014-05-01 18:19:12 +01002225 else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
Simon Kelley613ad152014-02-25 23:02:28 +00002226 chop_ns++;
Simon Kelley50f86ce2014-04-24 17:59:58 +01002227 else
2228 chop_ar++;
Simon Kelley613ad152014-02-25 23:02:28 +00002229 }
2230 else if (!ADD_RDLEN(header, p, plen, rdlen))
2231 return plen;
2232 }
2233
2234 /* Nothing to do. */
2235 if (rr_found == 0)
2236 return plen;
2237
2238 /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
2239 point to records we're going to elide. This is theoretically possible, but unlikely. If
2240 it happens, we give up and leave the answer unchanged. */
2241 p = (unsigned char *)(header+1);
2242
2243 /* question first */
2244 if (!check_name(&p, header, plen, 0, rrs, rr_found))
2245 return plen;
2246 p += 4; /* qclass, qtype */
2247
2248 /* Now answers and NS */
2249 if (!check_rrs(p, header, plen, 0, rrs, rr_found))
2250 return plen;
2251
2252 /* Third pass, elide records */
2253 for (p = rrs[0], i = 1; i < rr_found; i += 2)
2254 {
2255 unsigned char *start = rrs[i];
2256 unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
2257
2258 memmove(p, start, end-start);
2259 p += end-start;
2260 }
2261
2262 plen = p - (unsigned char *)header;
2263 header->ancount = htons(ntohs(header->ancount) - chop_an);
2264 header->nscount = htons(ntohs(header->nscount) - chop_ns);
Simon Kelley50f86ce2014-04-24 17:59:58 +01002265 header->arcount = htons(ntohs(header->arcount) - chop_ar);
2266
Simon Kelley613ad152014-02-25 23:02:28 +00002267 /* Fourth pass, fix up pointers in the remaining records */
2268 p = (unsigned char *)(header+1);
2269
2270 check_name(&p, header, plen, 1, rrs, rr_found);
2271 p += 4; /* qclass, qtype */
2272
2273 check_rrs(p, header, plen, 1, rrs, rr_found);
2274
2275 return plen;
2276}
2277
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002278unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2279{
2280 int q;
2281 unsigned int len;
2282 unsigned char *p = (unsigned char *)(header+1);
2283 const struct nettle_hash *hash;
2284 void *ctx;
2285 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002286
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002287 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2288 return NULL;
2289
2290 for (q = ntohs(header->qdcount); q != 0; q--)
2291 {
2292 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002293 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002294
2295 len = to_wire(name);
2296 hash->update(ctx, len, (unsigned char *)name);
2297 /* CRC the class and type as well */
2298 hash->update(ctx, 4, p);
2299
2300 p += 4;
2301 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002302 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002303 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002304
2305 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002306 return digest;
2307}
2308
Simon Kelley0fc2f312014-01-08 10:26:58 +00002309#endif /* HAVE_DNSSEC */