blob: 1aea2998c05b4e95fdc6bc727dd8041d5db469b8 [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;
1685
1686 /* Can't validate an RRISG query */
1687 if (qtype == T_RRSIG)
1688 return STAT_INSECURE;
1689
1690 cname_loop:
1691 for (j = ntohs(header->ancount); j != 0; j--)
1692 {
1693 /* leave pointer to missing name in qname */
1694
1695 if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001696 return STAT_BOGUS; /* bad packet */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001697
1698 GETSHORT(type2, p1);
1699 GETSHORT(class2, p1);
1700 p1 += 4; /* TTL */
1701 GETSHORT(rdlen2, p1);
1702
1703 if (rc == 1 && qclass == class2)
1704 {
1705 /* Do we have an answer for the question? */
1706 if (type2 == qtype)
1707 {
1708 have_answer = 1;
1709 break;
1710 }
1711 else if (type2 == T_CNAME)
1712 {
1713 qname = p1;
1714
1715 /* looped CNAMES */
1716 if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +00001717 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001718
1719 p1 = ans_start;
1720 goto cname_loop;
1721 }
1722 }
1723
1724 if (!ADD_RDLEN(header, p1, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001725 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001726 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001727
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001728 if (neganswer && !have_answer)
1729 *neganswer = 1;
Simon Kelley05756102014-03-01 18:07:57 +00001730
1731 /* No data, therefore no sigs */
1732 if (ntohs(header->ancount) + ntohs(header->nscount) == 0)
1733 return STAT_NO_SIG;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001734
Simon Kelley0fc2f312014-01-08 10:26:58 +00001735 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001736 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001737 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001738 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001739
1740 GETSHORT(type1, p1);
1741 GETSHORT(class1, p1);
1742 p1 += 4; /* TTL */
1743 GETSHORT(rdlen1, p1);
1744
1745 /* Don't try and validate RRSIGs! */
1746 if (type1 != T_RRSIG)
1747 {
1748 /* Check if we've done this RRset already */
1749 for (p2 = ans_start, j = 0; j < i; j++)
1750 {
1751 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001752 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001753
1754 GETSHORT(type2, p2);
1755 GETSHORT(class2, p2);
1756 p2 += 4; /* TTL */
1757 GETSHORT(rdlen2, p2);
1758
1759 if (type2 == type1 && class2 == class1 && rc == 1)
1760 break; /* Done it before: name, type, class all match. */
1761
1762 if (!ADD_RDLEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001763 return STAT_BOGUS;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001764 }
1765
1766 /* Not done, validate now */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001767 if (j == i)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001768 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001769 int ttl, keytag, algo, digest, type_covered;
1770 unsigned char *psave;
1771 struct all_addr a;
1772 struct blockdata *key;
1773 struct crec *crecp;
1774
Simon Kelley5107ace2014-02-23 10:48:32 +00001775 rc = validate_rrset(now, header, plen, class1, type1, name, keyname, NULL, 0, 0, 0);
1776
1777 if (rc == STAT_SECURE_WILDCARD)
1778 {
1779 /* An attacker replay a wildcard answer with a different
Simon Kelleya857daa2014-02-24 21:01:09 +00001780 answer and overlay a genuine RR. To prove this
Simon Kelley5107ace2014-02-23 10:48:32 +00001781 hasn't happened, the answer must prove that
Simon Kelleya857daa2014-02-24 21:01:09 +00001782 the gennuine record doesn't exist. Check that here. */
Simon Kelley87070192014-03-01 20:48:24 +00001783 if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
1784 return STAT_BOGUS; /* No NSECs or bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001785
1786 if (nsec_type == T_NSEC)
Simon Kelley24187532014-02-24 21:46:44 +00001787 rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
Simon Kelley5107ace2014-02-23 10:48:32 +00001788 else
Simon Kelley24187532014-02-24 21:46:44 +00001789 rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
Simon Kelley5107ace2014-02-23 10:48:32 +00001790
1791 if (rc != STAT_SECURE)
1792 return rc;
1793 }
1794 else if (rc != STAT_SECURE)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001795 {
1796 if (class)
1797 *class = class1; /* Class for DS or DNSKEY */
1798 return rc;
1799 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001800
Simon Kelley8d718cb2014-02-03 16:27:37 +00001801 /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
1802 cache_start_insert();
1803
1804 for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001805 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001806 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001807 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001808
1809 GETSHORT(type2, p2);
1810 GETSHORT(class2, p2);
1811 GETLONG(ttl, p2);
1812 GETSHORT(rdlen2, p2);
1813
1814 if (!CHECK_LEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001815 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001816
Simon Kelley8d718cb2014-02-03 16:27:37 +00001817 if (class2 == class1 && rc == 1)
1818 {
1819 psave = p2;
1820
1821 if (type1 == T_DS && type2 == T_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001822 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001823 if (rdlen2 < 4)
Simon Kelley87070192014-03-01 20:48:24 +00001824 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001825
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001826 GETSHORT(keytag, p2);
1827 algo = *p2++;
1828 digest = *p2++;
1829
1830 /* Cache needs to known class for DNSSEC stuff */
1831 a.addr.dnssec.class = class2;
1832
Simon Kelley8d718cb2014-02-03 16:27:37 +00001833 if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001834 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001835 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
1836 blockdata_free(key);
1837 else
1838 {
1839 a.addr.keytag = keytag;
1840 log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
1841 crecp->addr.ds.digest = digest;
1842 crecp->addr.ds.keydata = key;
1843 crecp->addr.ds.algo = algo;
1844 crecp->addr.ds.keytag = keytag;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001845 crecp->addr.ds.keylen = rdlen2 - 4;
1846 }
1847 }
1848 }
1849 else if (type2 == T_RRSIG)
1850 {
1851 if (rdlen2 < 18)
Simon Kelley87070192014-03-01 20:48:24 +00001852 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001853
Simon Kelley8d718cb2014-02-03 16:27:37 +00001854 GETSHORT(type_covered, p2);
1855
1856 if (type_covered == type1 &&
1857 (type_covered == T_A || type_covered == T_AAAA ||
1858 type_covered == T_CNAME || type_covered == T_DS ||
1859 type_covered == T_DNSKEY || type_covered == T_PTR))
1860 {
1861 a.addr.dnssec.type = type_covered;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001862 a.addr.dnssec.class = class1;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001863
1864 algo = *p2++;
1865 p2 += 13; /* labels, orig_ttl, expiration, inception */
1866 GETSHORT(keytag, p2);
1867
1868 if ((key = blockdata_alloc((char*)psave, rdlen2)))
1869 {
1870 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
1871 blockdata_free(key);
1872 else
1873 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001874 crecp->addr.sig.keydata = key;
1875 crecp->addr.sig.keylen = rdlen2;
1876 crecp->addr.sig.keytag = keytag;
1877 crecp->addr.sig.type_covered = type_covered;
1878 crecp->addr.sig.algo = algo;
1879 }
1880 }
1881 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001882 }
1883
Simon Kelley8d718cb2014-02-03 16:27:37 +00001884 p2 = psave;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001885 }
1886
Simon Kelley8d718cb2014-02-03 16:27:37 +00001887 if (!ADD_RDLEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001888 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001889 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001890
1891 cache_end_insert();
Simon Kelley0fc2f312014-01-08 10:26:58 +00001892 }
1893 }
1894
1895 if (!ADD_RDLEN(header, p1, plen, rdlen1))
Simon Kelley87070192014-03-01 20:48:24 +00001896 return STAT_BOGUS;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001897 }
1898
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001899 /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001900 if (have_answer)
1901 return STAT_SECURE;
1902
Simon Kelley5107ace2014-02-23 10:48:32 +00001903 /* NXDOMAIN or NODATA reply, prove that (name, class1, type1) can't exist */
Simon Kelley5107ace2014-02-23 10:48:32 +00001904 /* First marshall the NSEC records, if we've not done it previously */
Simon Kelley87070192014-03-01 20:48:24 +00001905 if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
1906 return STAT_BOGUS; /* No NSECs */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001907
1908 /* Get name of missing answer */
1909 if (!extract_name(header, plen, &qname, name, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +00001910 return STAT_BOGUS;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001911
Simon Kelley5107ace2014-02-23 10:48:32 +00001912 if (nsec_type == T_NSEC)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001913 return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
Simon Kelley5107ace2014-02-23 10:48:32 +00001914 else
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001915 return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
Giovanni Bajoadca3e92012-04-25 17:46:53 +02001916}
1917
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001918/* Chase the CNAME chain in the packet until the first record which _doesn't validate.
1919 Needed for proving answer in unsigned space.
1920 Return STAT_NEED_*
1921 STAT_BOGUS - error
1922 STAT_INSECURE - name of first non-secure record in name
1923*/
1924int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
1925{
1926 unsigned char *p = (unsigned char *)(header+1);
Simon Kelleyc07d30d2014-03-03 14:19:19 +00001927 int type, class, qclass, rdlen, j, rc;
Simon Kelley1fbe4d22014-03-01 20:03:47 +00001928 int cname_count = CNAME_CHAIN;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001929
1930 /* Get question */
1931 if (!extract_name(header, plen, &p, name, 1, 4))
1932 return STAT_BOGUS;
1933
Simon Kelleyc07d30d2014-03-03 14:19:19 +00001934 p +=2; /* type */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001935 GETSHORT(qclass, p);
1936
1937 while (1)
1938 {
1939 for (j = ntohs(header->ancount); j != 0; j--)
1940 {
1941 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
1942 return STAT_BOGUS; /* bad packet */
1943
1944 GETSHORT(type, p);
1945 GETSHORT(class, p);
1946 p += 4; /* TTL */
1947 GETSHORT(rdlen, p);
1948
1949 /* Not target, loop */
1950 if (rc == 2 || qclass != class)
1951 {
1952 if (!ADD_RDLEN(header, p, plen, rdlen))
1953 return STAT_BOGUS;
1954 continue;
1955 }
1956
1957 /* Got to end of CNAME chain. */
1958 if (type != T_CNAME)
1959 return STAT_INSECURE;
1960
1961 /* validate CNAME chain, return if insecure or need more data */
1962 rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, 0, 0, 0);
1963 if (rc != STAT_SECURE)
1964 {
1965 if (rc == STAT_NO_SIG)
1966 rc = STAT_INSECURE;
1967 return rc;
1968 }
1969
1970 /* Loop down CNAME chain/ */
1971 if (!cname_count-- ||
1972 !extract_name(header, plen, &p, name, 1, 0) ||
1973 !(p = skip_questions(header, plen)))
1974 return STAT_BOGUS;
1975
1976 break;
1977 }
1978
1979 /* End of CNAME chain */
1980 return STAT_INSECURE;
1981 }
1982}
1983
1984
Giovanni Bajo3471f182012-04-25 17:49:16 +02001985/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001986int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02001987{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001988 if (alg == 1)
1989 {
1990 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
1991 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001992 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001993 }
1994 else
1995 {
Simon Kelley1633e302014-02-10 16:42:46 +00001996 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001997 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02001998
Simon Kelley0fc2f312014-01-08 10:26:58 +00001999 for (i = 0; i < keylen; ++i)
2000 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002001
Simon Kelley0fc2f312014-01-08 10:26:58 +00002002 ac += (ac >> 16) & 0xffff;
2003 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002004 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002005}
2006
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002007size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr)
2008{
2009 unsigned char *p;
Simon Kelley610e7822014-02-06 14:45:17 +00002010 char *types = querystr("dnssec-query", type);
Giovanni Bajo0304d282012-05-02 03:29:52 +02002011
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002012 if (addr->sa.sa_family == AF_INET)
2013 log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
2014#ifdef HAVE_IPV6
2015 else
2016 log_query(F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
2017#endif
2018
2019 header->qdcount = htons(1);
2020 header->ancount = htons(0);
2021 header->nscount = htons(0);
2022 header->arcount = htons(0);
2023
2024 header->hb3 = HB3_RD;
2025 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002026 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2027 this allows it to select auth servers when one is returning bad data. */
2028 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002029
2030 /* ID filled in later */
2031
2032 p = (unsigned char *)(header+1);
2033
2034 p = do_rfc1035_name(p, name);
2035 *p++ = 0;
2036 PUTSHORT(type, p);
2037 PUTSHORT(class, p);
2038
2039 return add_do_bit(header, p - (unsigned char *)header, end);
2040}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002041
Simon Kelley613ad152014-02-25 23:02:28 +00002042/* Go through a domain name, find "pointers" and fix them up based on how many bytes
2043 we've chopped out of the packet, or check they don't point into an elided part. */
2044static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
2045{
2046 unsigned char *ansp = *namep;
2047
2048 while(1)
2049 {
2050 unsigned int label_type;
2051
2052 if (!CHECK_LEN(header, ansp, plen, 1))
2053 return 0;
2054
2055 label_type = (*ansp) & 0xc0;
2056
2057 if (label_type == 0xc0)
2058 {
2059 /* pointer for compression. */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002060 unsigned int offset;
2061 int i;
Simon Kelley613ad152014-02-25 23:02:28 +00002062 unsigned char *p;
2063
2064 if (!CHECK_LEN(header, ansp, plen, 2))
2065 return 0;
2066
2067 offset = ((*ansp++) & 0x3f) << 8;
2068 offset |= *ansp++;
2069
2070 p = offset + (unsigned char *)header;
2071
2072 for (i = 0; i < rr_count; i++)
2073 if (p < rrs[i])
2074 break;
2075 else
2076 if (i & 1)
2077 offset -= rrs[i] - rrs[i-1];
2078
2079 /* does the pointer end up in an elided RR? */
2080 if (i & 1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002081 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +00002082
2083 /* No, scale the pointer */
2084 if (fixup)
2085 {
2086 ansp -= 2;
2087 *ansp++ = (offset >> 8) | 0xc0;
2088 *ansp++ = offset & 0xff;
2089 }
2090 break;
2091 }
2092 else if (label_type == 0x80)
2093 return 0; /* reserved */
2094 else if (label_type == 0x40)
2095 {
2096 /* Extended label type */
2097 unsigned int count;
2098
2099 if (!CHECK_LEN(header, ansp, plen, 2))
2100 return 0;
2101
2102 if (((*ansp++) & 0x3f) != 1)
2103 return 0; /* we only understand bitstrings */
2104
2105 count = *(ansp++); /* Bits in bitstring */
2106
2107 if (count == 0) /* count == 0 means 256 bits */
2108 ansp += 32;
2109 else
2110 ansp += ((count-1)>>3)+1;
2111 }
2112 else
2113 { /* label type == 0 Bottom six bits is length */
2114 unsigned int len = (*ansp++) & 0x3f;
2115
2116 if (!ADD_RDLEN(header, ansp, plen, len))
2117 return 0;
2118
2119 if (len == 0)
2120 break; /* zero length label marks the end. */
2121 }
2122 }
2123
2124 *namep = ansp;
2125
2126 return 1;
2127}
2128
2129/* Go through RRs and check or fixup the domain names contained within */
2130static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
2131{
2132 int i, type, class, rdlen;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002133 unsigned char *pp;
Simon Kelley613ad152014-02-25 23:02:28 +00002134
Simon Kelley50f86ce2014-04-24 17:59:58 +01002135 for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
Simon Kelley613ad152014-02-25 23:02:28 +00002136 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002137 pp = p;
2138
2139 if (!(p = skip_name(p, header, plen, 10)))
2140 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +00002141
2142 GETSHORT(type, p);
2143 GETSHORT(class, p);
2144 p += 4; /* TTL */
2145 GETSHORT(rdlen, p);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002146
Simon Kelley613ad152014-02-25 23:02:28 +00002147 if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
2148 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002149 /* fixup name of RR */
2150 if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
2151 return 0;
2152
Simon Kelley613ad152014-02-25 23:02:28 +00002153 if (class == C_IN)
2154 {
2155 u16 *d;
Simon Kelley14db4212014-03-01 15:35:50 +00002156
2157 for (pp = p, d = get_desc(type); *d != (u16)-1; d++)
Simon Kelley613ad152014-02-25 23:02:28 +00002158 {
2159 if (*d != 0)
2160 pp += *d;
2161 else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
2162 return 0;
2163 }
2164 }
2165 }
2166
2167 if (!ADD_RDLEN(header, p, plen, rdlen))
2168 return 0;
2169 }
2170
2171 return 1;
2172}
2173
2174
2175size_t filter_rrsigs(struct dns_header *header, size_t plen)
2176{
2177 static unsigned char **rrs;
2178 static int rr_sz = 0;
2179
2180 unsigned char *p = (unsigned char *)(header+1);
Simon Kelley50f86ce2014-04-24 17:59:58 +01002181 int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
Simon Kelley613ad152014-02-25 23:02:28 +00002182
2183 if (ntohs(header->qdcount) != 1 ||
2184 !(p = skip_name(p, header, plen, 4)))
2185 return plen;
2186
2187 GETSHORT(qtype, p);
2188 GETSHORT(qclass, p);
2189
2190 /* First pass, find pointers to start and end of all the records we wish to elide:
2191 records added for DNSSEC, unless explicity queried for */
Simon Kelley50f86ce2014-04-24 17:59:58 +01002192 for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
2193 i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
2194 i++)
Simon Kelley613ad152014-02-25 23:02:28 +00002195 {
2196 unsigned char *pstart = p;
2197 int type, class;
2198
2199 if (!(p = skip_name(p, header, plen, 10)))
2200 return plen;
2201
2202 GETSHORT(type, p);
2203 GETSHORT(class, p);
2204 p += 4; /* TTL */
2205 GETSHORT(rdlen, p);
2206
2207 if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) &&
2208 (type != qtype || class != qclass))
2209 {
2210 if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
2211 return plen;
2212
2213 rrs[rr_found++] = pstart;
2214
2215 if (!ADD_RDLEN(header, p, plen, rdlen))
2216 return plen;
2217
2218 rrs[rr_found++] = p;
2219
2220 if (i < ntohs(header->ancount))
2221 chop_an++;
Simon Kelley50f86ce2014-04-24 17:59:58 +01002222 else if (i < ntohs(header->nscount))
Simon Kelley613ad152014-02-25 23:02:28 +00002223 chop_ns++;
Simon Kelley50f86ce2014-04-24 17:59:58 +01002224 else
2225 chop_ar++;
Simon Kelley613ad152014-02-25 23:02:28 +00002226 }
2227 else if (!ADD_RDLEN(header, p, plen, rdlen))
2228 return plen;
2229 }
2230
2231 /* Nothing to do. */
2232 if (rr_found == 0)
2233 return plen;
2234
2235 /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
2236 point to records we're going to elide. This is theoretically possible, but unlikely. If
2237 it happens, we give up and leave the answer unchanged. */
2238 p = (unsigned char *)(header+1);
2239
2240 /* question first */
2241 if (!check_name(&p, header, plen, 0, rrs, rr_found))
2242 return plen;
2243 p += 4; /* qclass, qtype */
2244
2245 /* Now answers and NS */
2246 if (!check_rrs(p, header, plen, 0, rrs, rr_found))
2247 return plen;
2248
2249 /* Third pass, elide records */
2250 for (p = rrs[0], i = 1; i < rr_found; i += 2)
2251 {
2252 unsigned char *start = rrs[i];
2253 unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
2254
2255 memmove(p, start, end-start);
2256 p += end-start;
2257 }
2258
2259 plen = p - (unsigned char *)header;
2260 header->ancount = htons(ntohs(header->ancount) - chop_an);
2261 header->nscount = htons(ntohs(header->nscount) - chop_ns);
Simon Kelley50f86ce2014-04-24 17:59:58 +01002262 header->arcount = htons(ntohs(header->arcount) - chop_ar);
2263
Simon Kelley613ad152014-02-25 23:02:28 +00002264 /* Fourth pass, fix up pointers in the remaining records */
2265 p = (unsigned char *)(header+1);
2266
2267 check_name(&p, header, plen, 1, rrs, rr_found);
2268 p += 4; /* qclass, qtype */
2269
2270 check_rrs(p, header, plen, 1, rrs, rr_found);
2271
2272 return plen;
2273}
2274
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002275unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2276{
2277 int q;
2278 unsigned int len;
2279 unsigned char *p = (unsigned char *)(header+1);
2280 const struct nettle_hash *hash;
2281 void *ctx;
2282 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002283
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002284 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2285 return NULL;
2286
2287 for (q = ntohs(header->qdcount); q != 0; q--)
2288 {
2289 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002290 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002291
2292 len = to_wire(name);
2293 hash->update(ctx, len, (unsigned char *)name);
2294 /* CRC the class and type as well */
2295 hash->update(ctx, 4, p);
2296
2297 p += 4;
2298 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002299 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002300 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002301
2302 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002303 return digest;
2304}
2305
Simon Kelley0fc2f312014-01-08 10:26:58 +00002306#endif /* HAVE_DNSSEC */