blob: d39ab85ed966361f1a2d06897e46f71057f9b70b [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>
Simon Kelley063efb32014-06-17 19:49:31 +010029#include <nettle/bignum.h>
30
Simon Kelleycdb755c2014-06-18 20:52:53 +010031/* Nettle-3.0 moved to a new API for DSA. We use a name that's defined in the new API
32 to detect Nettle-3, and invoke the backwards compatibility mode. */
33#ifdef dsa_params_init
34#include <nettle/dsa-compat.h>
35#endif
36
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000037
Giovanni Bajoe292e932012-04-22 14:32:02 +020038#define SERIAL_UNDEF -100
39#define SERIAL_EQ 0
40#define SERIAL_LT -1
41#define SERIAL_GT 1
42
Simon Kelley86bec2d2014-01-13 21:31:20 +000043/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
44static char *ds_digest_name(int digest)
45{
46 switch (digest)
47 {
48 case 1: return "sha1";
49 case 2: return "sha256";
50 case 3: return "gosthash94";
51 case 4: return "sha384";
52 default: return NULL;
53 }
54}
55
56/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
57static char *algo_digest_name(int algo)
58{
59 switch (algo)
60 {
61 case 1: return "md5";
62 case 3: return "sha1";
63 case 5: return "sha1";
64 case 6: return "sha1";
65 case 7: return "sha1";
66 case 8: return "sha256";
67 case 10: return "sha512";
68 case 12: return "gosthash94";
69 case 13: return "sha256";
70 case 14: return "sha384";
71 default: return NULL;
72 }
73}
74
75/* Find pointer to correct hash function in nettle library */
76static const struct nettle_hash *hash_find(char *name)
77{
78 int i;
79
80 if (!name)
81 return NULL;
82
83 for (i = 0; nettle_hashes[i]; i++)
84 {
85 if (strcmp(nettle_hashes[i]->name, name) == 0)
86 return nettle_hashes[i];
87 }
88
89 return NULL;
90}
91
92/* expand ctx and digest memory allocations if necessary and init hash function */
93static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
94{
95 static void *ctx = NULL;
96 static unsigned char *digest = NULL;
97 static unsigned int ctx_sz = 0;
98 static unsigned int digest_sz = 0;
99
100 void *new;
101
102 if (ctx_sz < hash->context_size)
103 {
104 if (!(new = whine_malloc(hash->context_size)))
105 return 0;
106 if (ctx)
107 free(ctx);
108 ctx = new;
109 ctx_sz = hash->context_size;
110 }
111
112 if (digest_sz < hash->digest_size)
113 {
114 if (!(new = whine_malloc(hash->digest_size)))
115 return 0;
116 if (digest)
117 free(digest);
118 digest = new;
119 digest_sz = hash->digest_size;
120 }
121
122 *ctxp = ctx;
123 *digestp = digest;
124
125 hash->init(ctx);
126
127 return 1;
128}
129
Simon Kelleycdb755c2014-06-18 20:52:53 +0100130static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
131 unsigned char *digest, int algo)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000132{
133 unsigned char *p;
134 size_t exp_len;
135
136 static struct rsa_public_key *key = NULL;
137 static mpz_t sig_mpz;
138
139 if (key == NULL)
140 {
141 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
142 return 0;
143
144 nettle_rsa_public_key_init(key);
145 mpz_init(sig_mpz);
146 }
147
148 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
149 return 0;
150
151 key_len--;
152 if ((exp_len = *p++) == 0)
153 {
154 GETSHORT(exp_len, p);
155 key_len -= 2;
156 }
157
158 if (exp_len >= key_len)
159 return 0;
160
161 key->size = key_len - exp_len;
162 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
163 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
164
165 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
166
167 switch (algo)
168 {
169 case 1:
170 return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
171 case 5: case 7:
172 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
173 case 8:
174 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
175 case 10:
176 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
177 }
178
179 return 0;
180}
181
Simon Kelleycdb755c2014-06-18 20:52:53 +0100182static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
183 unsigned char *digest, int algo)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000184{
185 unsigned char *p;
186 unsigned int t;
187
188 static struct dsa_public_key *key = NULL;
189 static struct dsa_signature *sig_struct;
190
191 if (key == NULL)
192 {
193 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
194 !(key = whine_malloc(sizeof(struct dsa_public_key))))
195 return 0;
196
197 nettle_dsa_public_key_init(key);
198 nettle_dsa_signature_init(sig_struct);
199 }
200
201 if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
202 return 0;
203
204 t = *p++;
205
206 if (key_len < (213 + (t * 24)))
207 return 0;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000208
Simon Kelley86bec2d2014-01-13 21:31:20 +0000209 mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
210 mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
211 mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
212 mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
213
214 mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
215 mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
216
217 (void)algo;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000218
Simon Kelley86bec2d2014-01-13 21:31:20 +0000219 return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
220}
221
Simon Kelleyc152dc82014-02-19 18:14:33 +0000222#ifndef NO_NETTLE_ECC
223static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
224 unsigned char *sig, size_t sig_len,
Simon Kelleyebe95a82014-02-13 14:56:10 +0000225 unsigned char *digest, size_t digest_len, int algo)
226{
227 unsigned char *p;
228 unsigned int t;
229 struct ecc_point *key;
230
231 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
232 static mpz_t x, y;
233 static struct dsa_signature *sig_struct;
234
235 if (!sig_struct)
236 {
237 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
238 return 0;
239
240 nettle_dsa_signature_init(sig_struct);
241 mpz_init(x);
242 mpz_init(y);
243 }
244
245 switch (algo)
246 {
247 case 13:
248 if (!key_256)
249 {
250 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
251 return 0;
252
253 nettle_ecc_point_init(key_256, &nettle_secp_256r1);
254 }
255
256 key = key_256;
257 t = 32;
258 break;
259
260 case 14:
261 if (!key_384)
262 {
263 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
264 return 0;
265
266 nettle_ecc_point_init(key_384, &nettle_secp_384r1);
267 }
268
269 key = key_384;
270 t = 48;
271 break;
272
273 default:
274 return 0;
275 }
276
277 if (sig_len != 2*t || key_len != 2*t ||
278 (p = blockdata_retrieve(key_data, key_len, NULL)))
279 return 0;
280
281 mpz_import(x, t , 1, 1, 0, 0, p);
282 mpz_import(y, t , 1, 1, 0, 0, p + t);
283
284 if (!ecc_point_set(key, x, y))
285 return 0;
286
287 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
288 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
289
290 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
291}
Simon Kelleyc152dc82014-02-19 18:14:33 +0000292#endif
293
Simon Kelley86bec2d2014-01-13 21:31:20 +0000294static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
Simon Kelleyebe95a82014-02-13 14:56:10 +0000295 unsigned char *digest, size_t digest_len, int algo)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000296{
Simon Kelley7b1eae42014-02-20 13:43:28 +0000297 (void)digest_len;
298
Simon Kelley86bec2d2014-01-13 21:31:20 +0000299 switch (algo)
300 {
301 case 1: case 5: case 7: case 8: case 10:
Simon Kelleycdb755c2014-06-18 20:52:53 +0100302 return dnsmasq_rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000303
304 case 3: case 6:
Simon Kelleycdb755c2014-06-18 20:52:53 +0100305 return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
Simon Kelleyc152dc82014-02-19 18:14:33 +0000306
307#ifndef NO_NETTLE_ECC
Simon Kelleyebe95a82014-02-13 14:56:10 +0000308 case 13: case 14:
309 return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
Simon Kelleyc152dc82014-02-19 18:14:33 +0000310#endif
311 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000312
313 return 0;
314}
315
Simon Kelley0fc2f312014-01-08 10:26:58 +0000316/* Convert from presentation format to wire format, in place.
317 Also map UC -> LC.
318 Note that using extract_name to get presentation format
319 then calling to_wire() removes compression and maps case,
320 thus generating names in canonical form.
321 Calling to_wire followed by from_wire is almost an identity,
322 except that the UC remains mapped to LC.
323*/
324static int to_wire(char *name)
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200325{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000326 unsigned char *l, *p, term;
327 int len;
328
329 for (l = (unsigned char*)name; *l != 0; l = p)
330 {
331 for (p = l; *p != '.' && *p != 0; p++)
332 if (*p >= 'A' && *p <= 'Z')
333 *p = *p - 'A' + 'a';
334
335 term = *p;
336
337 if ((len = p - l) != 0)
338 memmove(l+1, l, len);
339 *l = len;
340
341 p++;
342
343 if (term == 0)
344 *p = 0;
345 }
346
347 return l + 1 - (unsigned char *)name;
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200348}
349
Simon Kelley0fc2f312014-01-08 10:26:58 +0000350/* Note: no compression allowed in input. */
351static void from_wire(char *name)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200352{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000353 unsigned char *l;
354 int len;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200355
Simon Kelley0fc2f312014-01-08 10:26:58 +0000356 for (l = (unsigned char *)name; *l != 0; l += len+1)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200357 {
Simon Kelley0fc2f312014-01-08 10:26:58 +0000358 len = *l;
359 memmove(l, l+1, len);
360 l[len] = '.';
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200361 }
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200362
Simon Kelleye3f14552014-03-01 17:58:28 +0000363 if ((char *)l != name)
Simon Kelleybd9b3cf2014-03-01 16:12:28 +0000364 *(l-1) = 0;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200365}
366
Simon Kelley5ada8882014-01-09 22:25:03 +0000367/* Input in presentation format */
368static int count_labels(char *name)
369{
370 int i;
371
372 if (*name == 0)
373 return 0;
374
375 for (i = 0; *name; name++)
376 if (*name == '.')
377 i++;
378
379 return i+1;
380}
381
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000382/* Implement RFC1982 wrapped compare for 32-bit numbers */
383static int serial_compare_32(unsigned long s1, unsigned long s2)
Giovanni Bajo0852d762012-04-28 03:49:24 +0200384{
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000385 if (s1 == s2)
386 return SERIAL_EQ;
Giovanni Bajo0852d762012-04-28 03:49:24 +0200387
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000388 if ((s1 < s2 && (s2 - s1) < (1UL<<31)) ||
389 (s1 > s2 && (s1 - s2) > (1UL<<31)))
390 return SERIAL_LT;
391 if ((s1 < s2 && (s2 - s1) > (1UL<<31)) ||
392 (s1 > s2 && (s1 - s2) < (1UL<<31)))
393 return SERIAL_GT;
394 return SERIAL_UNDEF;
395}
Giovanni Bajo0852d762012-04-28 03:49:24 +0200396
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000397/* Check whether today/now is between date_start and date_end */
398static int check_date_range(unsigned long date_start, unsigned long date_end)
399{
Simon Kelleye98bd522014-03-28 20:41:23 +0000400 unsigned long curtime;
401
402 /* Checking timestamps may be temporarily disabled */
403 if (option_bool(OPT_DNSSEC_TIME))
404 return 1;
405
406 curtime = time(0);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000407
408 /* We must explicitly check against wanted values, because of SERIAL_UNDEF */
409 return serial_compare_32(curtime, date_start) == SERIAL_GT
410 && serial_compare_32(curtime, date_end) == SERIAL_LT;
411}
412
413static u16 *get_desc(int type)
414{
415 /* List of RRtypes which include domains in the data.
416 0 -> domain
417 integer -> no of plain bytes
418 -1 -> end
419
420 zero is not a valid RRtype, so the final entry is returned for
421 anything which needs no mangling.
422 */
423
424 static u16 rr_desc[] =
425 {
426 T_NS, 0, -1,
427 T_MD, 0, -1,
428 T_MF, 0, -1,
429 T_CNAME, 0, -1,
430 T_SOA, 0, 0, -1,
431 T_MB, 0, -1,
432 T_MG, 0, -1,
433 T_MR, 0, -1,
434 T_PTR, 0, -1,
435 T_MINFO, 0, 0, -1,
436 T_MX, 2, 0, -1,
437 T_RP, 0, 0, -1,
438 T_AFSDB, 2, 0, -1,
439 T_RT, 2, 0, -1,
440 T_SIG, 18, 0, -1,
441 T_PX, 2, 0, 0, -1,
442 T_NXT, 0, -1,
443 T_KX, 2, 0, -1,
444 T_SRV, 6, 0, -1,
445 T_DNAME, 0, -1,
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000446 0, -1 /* wildcard/catchall */
447 };
448
449 u16 *p = rr_desc;
450
451 while (*p != type && *p != 0)
452 while (*p++ != (u16)-1);
453
454 return p+1;
455}
456
457/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
458 data, pointed to by *p, should be used raw. */
Simon Kelley094b5c32014-12-21 16:11:52 +0000459static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000460 unsigned char **p, u16 **desc)
461{
462 int d = **desc;
463
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000464 /* No more data needs mangling */
465 if (d == (u16)-1)
Simon Kelley094b5c32014-12-21 16:11:52 +0000466 {
467 /* If there's more data than we have space for, just return what fits,
468 we'll get called again for more chunks */
469 if (end - *p > bufflen)
470 {
471 memcpy(buff, *p, bufflen);
472 *p += bufflen;
473 return bufflen;
474 }
475
476 return 0;
477 }
478
479 (*desc)++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000480
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000481 if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
482 /* domain-name, canonicalise */
483 return to_wire(buff);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000484 else
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000485 {
486 /* plain data preceding a domain-name, don't run off the end of the data */
487 if ((end - *p) < d)
488 d = end - *p;
489
490 if (d != 0)
491 {
492 memcpy(buff, *p, d);
493 *p += d;
494 }
495
496 return d;
497 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000498}
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000499
Simon Kelley613ad152014-02-25 23:02:28 +0000500static int expand_workspace(unsigned char ***wkspc, int *sz, int new)
501{
502 unsigned char **p;
503 int new_sz = *sz;
504
505 if (new_sz > new)
506 return 1;
507
508 if (new >= 100)
509 return 0;
510
511 new_sz += 5;
512
513 if (!(p = whine_malloc((new_sz) * sizeof(unsigned char **))))
514 return 0;
515
516 if (*wkspc)
517 {
518 memcpy(p, *wkspc, *sz * sizeof(unsigned char **));
519 free(*wkspc);
520 }
521
522 *wkspc = p;
523 *sz = new_sz;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000524
525 return 1;
Simon Kelley613ad152014-02-25 23:02:28 +0000526}
527
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000528/* Bubble sort the RRset into the canonical order.
529 Note that the byte-streams from two RRs may get unsynced: consider
530 RRs which have two domain-names at the start and then other data.
531 The domain-names may have different lengths in each RR, but sort equal
532
533 ------------
534 |abcde|fghi|
535 ------------
536 |abcd|efghi|
537 ------------
538
539 leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
540*/
541
542static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
543 unsigned char **rrset, char *buff1, char *buff2)
544{
545 int swap, quit, i;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000546
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000547 do
548 {
549 for (swap = 0, i = 0; i < rrsetidx-1; i++)
550 {
551 int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
552 u16 *dp1, *dp2;
553 unsigned char *end1, *end2;
Simon Kelley5107ace2014-02-23 10:48:32 +0000554 /* Note that these have been determined to be OK previously,
555 so we don't need to check for NULL return here. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000556 unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
557 unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
558
559 p1 += 8; /* skip class, type, ttl */
560 GETSHORT(rdlen1, p1);
561 end1 = p1 + rdlen1;
562
563 p2 += 8; /* skip class, type, ttl */
564 GETSHORT(rdlen2, p2);
565 end2 = p2 + rdlen2;
566
567 dp1 = dp2 = rr_desc;
568
Simon Kelley1486a9c2014-01-10 11:39:14 +0000569 for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000570 {
Simon Kelley1486a9c2014-01-10 11:39:14 +0000571 if (left1 != 0)
572 memmove(buff1, buff1 + len1 - left1, left1);
573
Simon Kelley094b5c32014-12-21 16:11:52 +0000574 if ((len1 = get_rdata(header, plen, end1, buff1 + left1, MAXDNAME - left1, &p1, &dp1)) == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000575 {
576 quit = 1;
577 len1 = end1 - p1;
578 memcpy(buff1 + left1, p1, len1);
579 }
580 len1 += left1;
581
Simon Kelley1486a9c2014-01-10 11:39:14 +0000582 if (left2 != 0)
583 memmove(buff2, buff2 + len2 - left2, left2);
584
Simon Kelley094b5c32014-12-21 16:11:52 +0000585 if ((len2 = get_rdata(header, plen, end2, buff2 + left2, MAXDNAME - left2, &p2, &dp2)) == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000586 {
587 quit = 1;
588 len2 = end2 - p2;
589 memcpy(buff2 + left2, p2, len2);
590 }
591 len2 += left2;
592
593 if (len1 > len2)
Simon Kelley1486a9c2014-01-10 11:39:14 +0000594 left1 = len1 - len2, left2 = 0, len = len2;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000595 else
Simon Kelley1486a9c2014-01-10 11:39:14 +0000596 left2 = len2 - len1, left1 = 0, len = len1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000597
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000598 rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000599
Simon Kelley4619d942014-01-16 19:53:06 +0000600 if (rc > 0 || (rc == 0 && quit && len1 > len2))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000601 {
602 unsigned char *tmp = rrset[i+1];
603 rrset[i+1] = rrset[i];
604 rrset[i] = tmp;
605 swap = quit = 1;
606 }
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000607 else if (rc < 0)
608 quit = 1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000609 }
610 }
611 } while (swap);
612}
613
614/* Validate a single RRset (class, type, name) in the supplied DNS reply
615 Return code:
616 STAT_SECURE if it validates.
Simon Kelley5107ace2014-02-23 10:48:32 +0000617 STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
Simon Kelleyfbc52052014-12-23 15:46:08 +0000618 (In this case *wildcard_out points to the "body" of the wildcard within name.)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000619 STAT_NO_SIG no RRsigs found.
Simon Kelley87070192014-03-01 20:48:24 +0000620 STAT_INSECURE RRset empty.
621 STAT_BOGUS signature is wrong, bad packet.
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000622 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
623
624 if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
625 otherwise find the key in the cache.
Simon Kelley5107ace2014-02-23 10:48:32 +0000626
627 name is unchanged on exit. keyname is used as workspace and trashed.
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000628*/
Simon Kelleyfbc52052014-12-23 15:46:08 +0000629static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type,
630 char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000631{
632 static unsigned char **rrset = NULL, **sigs = NULL;
633 static int rrset_sz = 0, sig_sz = 0;
634
635 unsigned char *p;
Simon Kelley5ada8882014-01-09 22:25:03 +0000636 int rrsetidx, sigidx, res, rdlen, j, name_labels;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000637 struct crec *crecp = NULL;
638 int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
639 u16 *rr_desc = get_desc(type);
Simon Kelley83d2ed02014-12-23 18:42:38 +0000640
641 if (wildcard_out)
642 *wildcard_out = NULL;
643
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000644 if (!(p = skip_questions(header, plen)))
Simon Kelley87070192014-03-01 20:48:24 +0000645 return STAT_BOGUS;
Simon Kelley83d2ed02014-12-23 18:42:38 +0000646
Simon Kelley5ada8882014-01-09 22:25:03 +0000647 name_labels = count_labels(name); /* For 4035 5.3.2 check */
648
649 /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000650 for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
651 j != 0; j--)
652 {
653 unsigned char *pstart, *pdata;
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000654 int stype, sclass;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000655
656 pstart = p;
657
658 if (!(res = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +0000659 return STAT_BOGUS; /* bad packet */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000660
661 GETSHORT(stype, p);
662 GETSHORT(sclass, p);
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000663 p += 4; /* TTL */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000664
665 pdata = p;
666
667 GETSHORT(rdlen, p);
668
Simon Kelleye7829ae2014-01-22 22:21:51 +0000669 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000670 return STAT_BOGUS;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000671
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000672 if (res == 1 && sclass == class)
673 {
674 if (stype == type)
675 {
Simon Kelley613ad152014-02-25 23:02:28 +0000676 if (!expand_workspace(&rrset, &rrset_sz, rrsetidx))
Simon Kelley87070192014-03-01 20:48:24 +0000677 return STAT_BOGUS;
Simon Kelley613ad152014-02-25 23:02:28 +0000678
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000679 rrset[rrsetidx++] = pstart;
680 }
681
682 if (stype == T_RRSIG)
683 {
Simon Kelley613ad152014-02-25 23:02:28 +0000684 if (rdlen < 18)
Simon Kelley87070192014-03-01 20:48:24 +0000685 return STAT_BOGUS; /* bad packet */
Simon Kelley613ad152014-02-25 23:02:28 +0000686
687 GETSHORT(type_covered, p);
688
689 if (type_covered == type)
690 {
691 if (!expand_workspace(&sigs, &sig_sz, sigidx))
Simon Kelley87070192014-03-01 20:48:24 +0000692 return STAT_BOGUS;
Simon Kelley613ad152014-02-25 23:02:28 +0000693
694 sigs[sigidx++] = pdata;
695 }
696
697 p = pdata + 2; /* restore for ADD_RDLEN */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000698 }
699 }
Simon Kelley613ad152014-02-25 23:02:28 +0000700
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000701 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000702 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000703 }
704
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000705 /* RRset empty */
706 if (rrsetidx == 0)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000707 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000708
709 /* no RRSIGs */
710 if (sigidx == 0)
711 return STAT_NO_SIG;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000712
713 /* Sort RRset records into canonical order.
Simon Kelleyd3873802014-02-23 16:20:46 +0000714 Note that at this point keyname and daemon->workspacename buffs are
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000715 unused, and used as workspace by the sort. */
Simon Kelleyd3873802014-02-23 16:20:46 +0000716 sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000717
718 /* Now try all the sigs to try and find one which validates */
719 for (j = 0; j <sigidx; j++)
720 {
Simon Kelleyd3873802014-02-23 16:20:46 +0000721 unsigned char *psav, *sig, *digest;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000722 int i, wire_len, sig_len;
723 const struct nettle_hash *hash;
724 void *ctx;
Simon Kelleyd3873802014-02-23 16:20:46 +0000725 char *name_start;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000726 u32 nsigttl;
727
728 p = sigs[j];
Simon Kelley5ada8882014-01-09 22:25:03 +0000729 GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000730 psav = p;
731
Simon Kelley5ada8882014-01-09 22:25:03 +0000732 p += 2; /* type_covered - already checked */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000733 algo = *p++;
734 labels = *p++;
735 GETLONG(orig_ttl, p);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000736 GETLONG(sig_expiration, p);
737 GETLONG(sig_inception, p);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000738 GETSHORT(key_tag, p);
739
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000740 if (!extract_name(header, plen, &p, keyname, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +0000741 return STAT_BOGUS;
Simon Kelleyd3873802014-02-23 16:20:46 +0000742
743 /* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
744 the name of the zone containing the RRset. We can't tell that
745 for certain, but we can check that the RRset name is equal to
746 or encloses the signers name, which should be enough to stop
747 an attacker using signatures made with the key of an unrelated
748 zone he controls. Note that the root key is always allowed. */
749 if (*keyname != 0)
750 {
751 int failed = 0;
752
753 for (name_start = name; !hostname_isequal(name_start, keyname); )
754 if ((name_start = strchr(name_start, '.')))
755 name_start++; /* chop a label off and try again */
756 else
757 {
758 failed = 1;
759 break;
760 }
761
762 /* Bad sig, try another */
763 if (failed)
764 continue;
765 }
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000766
Simon Kelleyd3873802014-02-23 16:20:46 +0000767 /* Other 5.3.1 checks */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000768 if (!check_date_range(sig_inception, sig_expiration) ||
769 labels > name_labels ||
770 !(hash = hash_find(algo_digest_name(algo))) ||
771 !hash_init(hash, &ctx, &digest))
772 continue;
773
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000774 /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
775 if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
776 return STAT_NEED_KEY;
777
Simon Kelley86bec2d2014-01-13 21:31:20 +0000778 sig = p;
779 sig_len = rdlen - (p - psav);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000780
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000781 nsigttl = htonl(orig_ttl);
782
Simon Kelley86bec2d2014-01-13 21:31:20 +0000783 hash->update(ctx, 18, psav);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000784 wire_len = to_wire(keyname);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000785 hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000786 from_wire(keyname);
787
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000788 for (i = 0; i < rrsetidx; ++i)
789 {
790 int seg;
791 unsigned char *end, *cp;
792 u16 len, *dp;
Simon Kelleyd3873802014-02-23 16:20:46 +0000793
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000794 p = rrset[i];
795 if (!extract_name(header, plen, &p, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +0000796 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000797
Simon Kelleyd3873802014-02-23 16:20:46 +0000798 name_start = name;
799
Simon Kelley5ada8882014-01-09 22:25:03 +0000800 /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
801 if (labels < name_labels)
802 {
803 int k;
804 for (k = name_labels - labels; k != 0; k--)
Simon Kelleyfbc52052014-12-23 15:46:08 +0000805 {
806 while (*name_start != '.' && *name_start != 0)
807 name_start++;
Simon Kelley0b1008d2014-12-27 15:33:32 +0000808 if (k != 1 && *name_start == '.')
Simon Kelleyfbc52052014-12-23 15:46:08 +0000809 name_start++;
810 }
811
812 if (wildcard_out)
813 *wildcard_out = name_start+1;
814
Simon Kelley5ada8882014-01-09 22:25:03 +0000815 name_start--;
816 *name_start = '*';
817 }
818
819 wire_len = to_wire(name_start);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000820 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
821 hash->update(ctx, 4, p); /* class and type */
822 hash->update(ctx, 4, (unsigned char *)&nsigttl);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000823
824 p += 8; /* skip class, type, ttl */
825 GETSHORT(rdlen, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000826 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +0000827 return STAT_BOGUS;
Simon Kelley5ada8882014-01-09 22:25:03 +0000828
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000829 end = p + rdlen;
830
831 /* canonicalise rdata and calculate length of same, use name buffer as workspace */
832 cp = p;
833 dp = rr_desc;
Simon Kelley094b5c32014-12-21 16:11:52 +0000834 for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)) != 0; len += seg);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000835 len += end - cp;
836 len = htons(len);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000837 hash->update(ctx, 2, (unsigned char *)&len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000838
839 /* Now canonicalise again and digest. */
840 cp = p;
841 dp = rr_desc;
Simon Kelley094b5c32014-12-21 16:11:52 +0000842 while ((seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000843 hash->update(ctx, seg, (unsigned char *)name);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000844 if (cp != end)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000845 hash->update(ctx, end - cp, cp);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000846 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000847
848 hash->digest(ctx, hash->digest_size, digest);
849
Simon Kelley5ada8882014-01-09 22:25:03 +0000850 /* namebuff used for workspace above, restore to leave unchanged on exit */
851 p = (unsigned char*)(rrset[0]);
852 extract_name(header, plen, &p, name, 1, 0);
853
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000854 if (key)
855 {
856 if (algo_in == algo && keytag_in == key_tag &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000857 verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000858 return STAT_SECURE;
859 }
860 else
861 {
862 /* iterate through all possible keys 4035 5.3.1 */
863 for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000864 if (crecp->addr.key.algo == algo &&
865 crecp->addr.key.keytag == key_tag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000866 crecp->uid == (unsigned int)class &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000867 verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5107ace2014-02-23 10:48:32 +0000868 return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000869 }
870 }
871
872 return STAT_BOGUS;
873}
874
Simon Kelley0fc2f312014-01-08 10:26:58 +0000875/* The DNS packet is expected to contain the answer to a DNSKEY query.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000876 Put all DNSKEYs in the answer which are valid into the cache.
877 return codes:
Simon Kelley97e618a2015-01-07 21:55:43 +0000878 STAT_SECURE At least one valid DNSKEY found and in cache.
Simon Kelley0fc2f312014-01-08 10:26:58 +0000879 STAT_BOGUS No DNSKEYs found, which can be validated with DS,
Simon Kelley87070192014-03-01 20:48:24 +0000880 or self-sign for DNSKEY RRset is not valid, bad packet.
Simon Kelley0fc2f312014-01-08 10:26:58 +0000881 STAT_NEED_DS DS records to validate a key not found, name in keyname
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000882*/
883int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
884{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000885 unsigned char *psave, *p = (unsigned char *)(header+1);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000886 struct crec *crecp, *recp1;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000887 int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000888 struct blockdata *key;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000889 struct all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000890
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000891 if (ntohs(header->qdcount) != 1 ||
892 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +0000893 return STAT_BOGUS;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000894
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000895 GETSHORT(qtype, p);
896 GETSHORT(qclass, p);
897
Simon Kelley97e618a2015-01-07 21:55:43 +0000898 if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000899 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000900
Simon Kelleyb8eac192014-02-27 14:30:03 +0000901 /* See if we have cached a DS record which validates this key */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000902 if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
903 {
904 strcpy(keyname, name);
905 return STAT_NEED_DS;
906 }
Simon Kelleyb8eac192014-02-27 14:30:03 +0000907
908 /* If we've cached that DS provably doesn't exist, result must be INSECURE */
909 if (crecp->flags & F_NEG)
910 return STAT_INSECURE;
911
Simon Kelley0fc2f312014-01-08 10:26:58 +0000912 /* NOTE, we need to find ONE DNSKEY which matches the DS */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000913 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000914 {
915 /* Ensure we have type, class TTL and length */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000916 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +0000917 return STAT_BOGUS; /* bad packet */
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000918
919 GETSHORT(qtype, p);
920 GETSHORT(qclass, p);
921 GETLONG(ttl, p);
922 GETSHORT(rdlen, p);
Simon Kelley6f468102014-01-26 23:39:17 +0000923
Simon Kelley0fc2f312014-01-08 10:26:58 +0000924 if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +0000925 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000926
Simon Kelley6f468102014-01-26 23:39:17 +0000927 if (qclass != class || qtype != T_DNSKEY || rc == 2)
928 {
929 p += rdlen;
930 continue;
931 }
932
Simon Kelley0fc2f312014-01-08 10:26:58 +0000933 psave = p;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000934
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000935 GETSHORT(flags, p);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000936 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +0000937 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000938 algo = *p++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000939 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000940 key = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000941
Simon Kelleye7829ae2014-01-22 22:21:51 +0000942 /* key must have zone key flag set */
943 if (flags & 0x100)
944 key = blockdata_alloc((char*)p, rdlen - 4);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000945
946 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000947
Simon Kelley0fc2f312014-01-08 10:26:58 +0000948 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000949 {
950 if (key)
951 blockdata_free(key);
Simon Kelley87070192014-03-01 20:48:24 +0000952 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000953 }
954
Simon Kelleye7829ae2014-01-22 22:21:51 +0000955 /* No zone key flag or malloc failure */
956 if (!key)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000957 continue;
958
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000959 for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000960 {
961 void *ctx;
962 unsigned char *digest, *ds_digest;
963 const struct nettle_hash *hash;
964
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000965 if (recp1->addr.ds.algo == algo &&
966 recp1->addr.ds.keytag == keytag &&
Simon Kelley3f7483e2014-03-16 22:56:58 +0000967 recp1->uid == (unsigned int)class &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000968 (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
Simon Kelley86bec2d2014-01-13 21:31:20 +0000969 hash_init(hash, &ctx, &digest))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000970
Simon Kelley86bec2d2014-01-13 21:31:20 +0000971 {
972 int wire_len = to_wire(name);
973
974 /* Note that digest may be different between DSs, so
975 we can't move this outside the loop. */
976 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
977 hash->update(ctx, (unsigned int)rdlen, psave);
978 hash->digest(ctx, hash->digest_size, digest);
979
980 from_wire(name);
981
Simon Kelley824202e2014-01-23 20:59:46 +0000982 if (recp1->addr.ds.keylen == (int)hash->digest_size &&
983 (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
984 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
Simon Kelleyfbc52052014-12-23 15:46:08 +0000985 validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000986 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000987 valid = 1;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000988 break;
989 }
990 }
991 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000992 blockdata_free(key);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000993 }
994
995 if (valid)
996 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000997 /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000998 cache_start_insert();
999
1000 p = skip_questions(header, plen);
1001
1002 for (j = ntohs(header->ancount); j != 0; j--)
1003 {
1004 /* Ensure we have type, class TTL and length */
1005 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
1006 return STAT_INSECURE; /* bad packet */
1007
1008 GETSHORT(qtype, p);
1009 GETSHORT(qclass, p);
1010 GETLONG(ttl, p);
1011 GETSHORT(rdlen, p);
Simon Kelley8d718cb2014-02-03 16:27:37 +00001012
1013 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001014 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +00001015
Simon Kelley8d718cb2014-02-03 16:27:37 +00001016 if (qclass == class && rc == 1)
Simon Kelleye7829ae2014-01-22 22:21:51 +00001017 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001018 psave = p;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001019
Simon Kelley8d718cb2014-02-03 16:27:37 +00001020 if (qtype == T_DNSKEY)
1021 {
1022 if (rdlen < 4)
Simon Kelley87070192014-03-01 20:48:24 +00001023 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001024
1025 GETSHORT(flags, p);
1026 if (*p++ != 3)
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001027 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001028 algo = *p++;
1029 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
1030
1031 /* Cache needs to known class for DNSSEC stuff */
1032 a.addr.dnssec.class = class;
1033
1034 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
1035 {
1036 if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
1037 blockdata_free(key);
1038 else
1039 {
1040 a.addr.keytag = keytag;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001041 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
Simon Kelley8d718cb2014-02-03 16:27:37 +00001042
1043 recp1->addr.key.keylen = rdlen - 4;
1044 recp1->addr.key.keydata = key;
1045 recp1->addr.key.algo = algo;
1046 recp1->addr.key.keytag = keytag;
1047 recp1->addr.key.flags = flags;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001048 }
1049 }
1050 }
1051 else if (qtype == T_RRSIG)
1052 {
1053 /* RRSIG, cache if covers DNSKEY RRset */
1054 if (rdlen < 18)
Simon Kelley87070192014-03-01 20:48:24 +00001055 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001056
1057 GETSHORT(type_covered, p);
1058
1059 if (type_covered == T_DNSKEY)
1060 {
1061 a.addr.dnssec.class = class;
1062 a.addr.dnssec.type = type_covered;
1063
1064 algo = *p++;
1065 p += 13; /* labels, orig_ttl, expiration, inception */
1066 GETSHORT(keytag, p);
1067 if ((key = blockdata_alloc((char*)psave, rdlen)))
1068 {
1069 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
1070 blockdata_free(key);
1071 else
1072 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001073 crecp->addr.sig.keydata = key;
1074 crecp->addr.sig.keylen = rdlen;
1075 crecp->addr.sig.keytag = keytag;
1076 crecp->addr.sig.type_covered = type_covered;
1077 crecp->addr.sig.algo = algo;
1078 }
1079 }
1080 }
1081 }
Simon Kelleye7829ae2014-01-22 22:21:51 +00001082
Simon Kelley8d718cb2014-02-03 16:27:37 +00001083 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001084 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001085
Simon Kelleye7829ae2014-01-22 22:21:51 +00001086 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001087 return STAT_BOGUS; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +00001088 }
1089
Simon Kelley0fc2f312014-01-08 10:26:58 +00001090 /* commit cache insert. */
1091 cache_end_insert();
1092 return STAT_SECURE;
1093 }
1094
Simon Kelley25cf5e32015-01-09 15:53:03 +00001095 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
Simon Kelley0fc2f312014-01-08 10:26:58 +00001096 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001097}
Simon Kelley0fc2f312014-01-08 10:26:58 +00001098
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001099/* The DNS packet is expected to contain the answer to a DS query
1100 Put all DSs in the answer which are valid into the cache.
1101 return codes:
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001102 STAT_SECURE At least one valid DS found and in cache.
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001103 STAT_NO_DS It's proved there's no DS here.
Simon Kelley97e618a2015-01-07 21:55:43 +00001104 STAT_NO_NS It's proved there's no DS _or_ NS here.
1105 STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001106 STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
1107*/
1108
1109int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
1110{
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001111 unsigned char *p = (unsigned char *)(header+1);
Simon Kelley97e618a2015-01-07 21:55:43 +00001112 int qtype, qclass, val, i, neganswer, nons;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001113
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001114 if (ntohs(header->qdcount) != 1 ||
Simon Kelleyb8eac192014-02-27 14:30:03 +00001115 !(p = skip_name(p, header, plen, 4)))
Simon Kelley87070192014-03-01 20:48:24 +00001116 return STAT_BOGUS;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001117
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001118 GETSHORT(qtype, p);
1119 GETSHORT(qclass, p);
1120
Simon Kelleyb47b04c2014-02-25 23:13:28 +00001121 if (qtype != T_DS || qclass != class)
1122 val = STAT_BOGUS;
1123 else
Simon Kelley97e618a2015-01-07 21:55:43 +00001124 val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, &neganswer, &nons);
1125 /* Note dnssec_validate_reply() will have cached positive answers */
1126
1127 if (val == STAT_NO_SIG || val == STAT_INSECURE)
1128 val = STAT_BOGUS;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001129
Simon Kelleyb8eac192014-02-27 14:30:03 +00001130 p = (unsigned char *)(header+1);
1131 extract_name(header, plen, &p, name, 1, 4);
1132 p += 4; /* qtype, qclass */
1133
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001134 if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001135 val = STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001136
Simon Kelley0fc2f312014-01-08 10:26:58 +00001137 if (val == STAT_BOGUS)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001138 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001139 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
Simon Kelley97e618a2015-01-07 21:55:43 +00001140 return STAT_BOGUS;
1141 }
1142
1143 /* By here, the answer is proved secure, and a positive answer has been cached. */
1144 if (val == STAT_SECURE && neganswer)
1145 {
1146 int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001147 unsigned long ttl, minttl = ULONG_MAX;
1148 struct all_addr a;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001149
1150 if (RCODE(header) == NXDOMAIN)
1151 flags |= F_NXDOMAIN;
1152
Simon Kelley97e618a2015-01-07 21:55:43 +00001153 /* We only cache validated DS records, DNSSECOK flag hijacked
1154 to store presence/absence of NS. */
1155 if (nons)
1156 flags &= ~F_DNSSECOK;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001157
1158 for (i = ntohs(header->nscount); i != 0; i--)
1159 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001160 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001161 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001162
1163 GETSHORT(qtype, p);
1164 GETSHORT(qclass, p);
1165 GETLONG(ttl, p);
1166 GETSHORT(rdlen, p);
1167
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001168 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001169 return STAT_BOGUS; /* bad packet */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001170
1171 if (qclass != class || qtype != T_SOA)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001172 {
1173 p += rdlen;
1174 continue;
1175 }
1176
1177 if (ttl < minttl)
1178 minttl = ttl;
1179
1180 /* MNAME */
1181 if (!(p = skip_name(p, header, plen, 0)))
Simon Kelley87070192014-03-01 20:48:24 +00001182 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001183 /* RNAME */
1184 if (!(p = skip_name(p, header, plen, 20)))
Simon Kelley87070192014-03-01 20:48:24 +00001185 return STAT_BOGUS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001186 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
1187
1188 GETLONG(ttl, p); /* minTTL */
1189 if (ttl < minttl)
1190 minttl = ttl;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001191
1192 break;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001193 }
1194
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001195 if (i != 0)
1196 {
1197 cache_start_insert();
1198
1199 a.addr.dnssec.class = class;
1200 cache_insert(name, &a, now, ttl, flags);
1201
Simon Kelley97e618a2015-01-07 21:55:43 +00001202 cache_end_insert();
1203
Simon Kelley25cf5e32015-01-09 15:53:03 +00001204 log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no delegation" : "no DS");
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001205 }
Simon Kelleyb8eac192014-02-27 14:30:03 +00001206
Simon Kelley97e618a2015-01-07 21:55:43 +00001207 return nons ? STAT_NO_NS : STAT_NO_DS;
Simon Kelleyb8eac192014-02-27 14:30:03 +00001208 }
1209
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001210 return val;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001211}
1212
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001213/* 4034 6.1 */
1214static int hostname_cmp(const char *a, const char *b)
1215{
Simon Kelleydbf72122014-01-21 14:28:02 +00001216 char *sa, *ea, *ca, *sb, *eb, *cb;
1217 unsigned char ac, bc;
1218
1219 sa = ea = (char *)a + strlen(a);
1220 sb = eb = (char *)b + strlen(b);
1221
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001222 while (1)
1223 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001224 while (sa != a && *(sa-1) != '.')
1225 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001226
Simon Kelleydbf72122014-01-21 14:28:02 +00001227 while (sb != b && *(sb-1) != '.')
1228 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001229
Simon Kelleydbf72122014-01-21 14:28:02 +00001230 ca = sa;
1231 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001232
Simon Kelleydbf72122014-01-21 14:28:02 +00001233 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001234 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001235 if (ca == ea)
1236 {
1237 if (cb == eb)
1238 break;
1239
1240 return -1;
1241 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001242
Simon Kelleydbf72122014-01-21 14:28:02 +00001243 if (cb == eb)
1244 return 1;
1245
1246 ac = (unsigned char) *ca++;
1247 bc = (unsigned char) *cb++;
1248
1249 if (ac >= 'A' && ac <= 'Z')
1250 ac += 'a' - 'A';
1251 if (bc >= 'A' && bc <= 'Z')
1252 bc += 'a' - 'A';
1253
Simon Kelley979cdf92014-01-21 16:26:41 +00001254 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001255 return -1;
1256 else if (ac != bc)
1257 return 1;
1258 }
1259
1260
1261 if (sa == a)
1262 {
1263 if (sb == b)
1264 return 0;
1265
1266 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001267 }
1268
Simon Kelleydbf72122014-01-21 14:28:02 +00001269 if (sb == b)
1270 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001271
Simon Kelleydbf72122014-01-21 14:28:02 +00001272 ea = sa--;
1273 eb = sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001274 }
1275}
1276
Simon Kelley5107ace2014-02-23 10:48:32 +00001277/* Find all the NSEC or NSEC3 records in a reply.
1278 return an array of pointers to them. */
1279static int find_nsec_records(struct dns_header *header, size_t plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd)
1280{
1281 static unsigned char **nsecset = NULL;
1282 static int nsecset_sz = 0;
1283
Simon Kelley87070192014-03-01 20:48:24 +00001284 int type_found = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001285 unsigned char *p = skip_questions(header, plen);
1286 int type, class, rdlen, i, nsecs_found;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001287
Simon Kelley5107ace2014-02-23 10:48:32 +00001288 /* Move to NS section */
1289 if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
1290 return 0;
1291
1292 for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
1293 {
1294 unsigned char *pstart = p;
1295
1296 if (!(p = skip_name(p, header, plen, 10)))
1297 return 0;
1298
1299 GETSHORT(type, p);
1300 GETSHORT(class, p);
1301 p += 4; /* TTL */
1302 GETSHORT(rdlen, p);
1303
1304 if (class == class_reqd && (type == T_NSEC || type == T_NSEC3))
1305 {
1306 /* No mixed NSECing 'round here, thankyouverymuch */
1307 if (type_found == T_NSEC && type == T_NSEC3)
1308 return 0;
1309 if (type_found == T_NSEC3 && type == T_NSEC)
1310 return 0;
1311
1312 type_found = type;
1313
Simon Kelley613ad152014-02-25 23:02:28 +00001314 if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
1315 return 0;
1316
Simon Kelley5107ace2014-02-23 10:48:32 +00001317 nsecset[nsecs_found++] = pstart;
1318 }
Simon Kelley613ad152014-02-25 23:02:28 +00001319
Simon Kelley5107ace2014-02-23 10:48:32 +00001320 if (!ADD_RDLEN(header, p, plen, rdlen))
1321 return 0;
1322 }
1323
1324 *nsecsetp = nsecset;
1325 *nsecsetl = nsecs_found;
1326
1327 return type_found;
1328}
1329
Simon Kelley24187532014-02-24 21:46:44 +00001330static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
Simon Kelley97e618a2015-01-07 21:55:43 +00001331 char *workspace1, char *workspace2, char *name, int type, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001332{
1333 int i, rc, rdlen;
1334 unsigned char *p, *psave;
1335 int offset = (type & 0xff) >> 3;
1336 int mask = 0x80 >> (type & 0x07);
Simon Kelley97e618a2015-01-07 21:55:43 +00001337
1338 if (nons)
1339 *nons = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001340
1341 /* Find NSEC record that proves name doesn't exist */
1342 for (i = 0; i < nsec_count; i++)
1343 {
1344 p = nsecs[i];
1345 if (!extract_name(header, plen, &p, workspace1, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001346 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001347 p += 8; /* class, type, TTL */
1348 GETSHORT(rdlen, p);
1349 psave = p;
1350 if (!extract_name(header, plen, &p, workspace2, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001351 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001352
1353 rc = hostname_cmp(workspace1, name);
1354
1355 if (rc == 0)
1356 {
Simon Kelleyf01d7be2014-02-24 20:20:00 +00001357 /* 4035 para 5.4. Last sentence */
1358 if (type == T_NSEC || type == T_RRSIG)
1359 return STAT_SECURE;
1360
Simon Kelley5107ace2014-02-23 10:48:32 +00001361 /* NSEC with the same name as the RR we're testing, check
1362 that the type in question doesn't appear in the type map */
1363 rdlen -= p - psave;
1364 /* rdlen is now length of type map, and p points to it */
1365
Simon Kelley97e618a2015-01-07 21:55:43 +00001366 /* If we can prove that there's no NS record, return that information. */
1367 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
1368 *nons = 1;
1369
Simon Kelley5107ace2014-02-23 10:48:32 +00001370 while (rdlen >= 2)
1371 {
1372 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelley87070192014-03-01 20:48:24 +00001373 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001374
1375 if (p[0] == type >> 8)
1376 {
1377 /* Does the NSEC say our type exists? */
Simon Kelleya857daa2014-02-24 21:01:09 +00001378 if (offset < p[1] && (p[offset+2] & mask) != 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001379 return STAT_BOGUS;
1380
1381 break; /* finshed checking */
1382 }
1383
1384 rdlen -= p[1];
1385 p += p[1];
1386 }
1387
1388 return STAT_SECURE;
1389 }
1390 else if (rc == -1)
1391 {
1392 /* Normal case, name falls between NSEC name and next domain name,
1393 wrap around case, name falls between NSEC name (rc == -1) and end */
1394 if (hostname_cmp(workspace2, name) == 1 || hostname_cmp(workspace1, workspace2) == 1)
1395 return STAT_SECURE;
1396 }
1397 else
1398 {
1399 /* wrap around case, name falls between start and next domain name */
1400 if (hostname_cmp(workspace1, workspace2) == 1 && hostname_cmp(workspace2, name) == 1)
1401 return STAT_SECURE;
1402 }
1403 }
1404
1405 return STAT_BOGUS;
1406}
1407
1408/* return digest length, or zero on error */
1409static int hash_name(char *in, unsigned char **out, struct nettle_hash const *hash,
1410 unsigned char *salt, int salt_len, int iterations)
1411{
1412 void *ctx;
1413 unsigned char *digest;
1414 int i;
1415
1416 if (!hash_init(hash, &ctx, &digest))
1417 return 0;
1418
1419 hash->update(ctx, to_wire(in), (unsigned char *)in);
1420 hash->update(ctx, salt_len, salt);
1421 hash->digest(ctx, hash->digest_size, digest);
1422
1423 for(i = 0; i < iterations; i++)
1424 {
1425 hash->update(ctx, hash->digest_size, digest);
1426 hash->update(ctx, salt_len, salt);
1427 hash->digest(ctx, hash->digest_size, digest);
1428 }
1429
1430 from_wire(in);
1431
1432 *out = digest;
1433 return hash->digest_size;
1434}
1435
1436/* Decode base32 to first "." or end of string */
1437static int base32_decode(char *in, unsigned char *out)
1438{
Simon Kelleya857daa2014-02-24 21:01:09 +00001439 int oc, on, c, mask, i;
Simon Kelley5107ace2014-02-23 10:48:32 +00001440 unsigned char *p = out;
1441
Simon Kelleya857daa2014-02-24 21:01:09 +00001442 for (c = *in, oc = 0, on = 0; c != 0 && c != '.'; c = *++in)
Simon Kelley5107ace2014-02-23 10:48:32 +00001443 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001444 if (c >= '0' && c <= '9')
1445 c -= '0';
1446 else if (c >= 'a' && c <= 'v')
1447 c -= 'a', c += 10;
1448 else if (c >= 'A' && c <= 'V')
1449 c -= 'A', c += 10;
1450 else
1451 return 0;
1452
1453 for (mask = 0x10, i = 0; i < 5; i++)
1454 {
Simon Kelleya857daa2014-02-24 21:01:09 +00001455 if (c & mask)
1456 oc |= 1;
1457 mask = mask >> 1;
1458 if (((++on) & 7) == 0)
1459 *p++ = oc;
1460 oc = oc << 1;
Simon Kelley5107ace2014-02-23 10:48:32 +00001461 }
1462 }
1463
1464 if ((on & 7) != 0)
1465 return 0;
1466
1467 return p - out;
1468}
1469
Simon Kelleyfbc52052014-12-23 15:46:08 +00001470static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
Simon Kelley97e618a2015-01-07 21:55:43 +00001471 char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
Simon Kelleyfbc52052014-12-23 15:46:08 +00001472{
1473 int i, hash_len, salt_len, base32_len, rdlen;
1474 unsigned char *p, *psave;
1475
1476 for (i = 0; i < nsec_count; i++)
1477 if ((p = nsecs[i]))
1478 {
1479 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
1480 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
1481 return 0;
1482
1483 p += 8; /* class, type, TTL */
1484 GETSHORT(rdlen, p);
1485 psave = p;
1486 p += 4; /* algo, flags, iterations */
1487 salt_len = *p++; /* salt_len */
1488 p += salt_len; /* salt */
1489 hash_len = *p++; /* p now points to next hashed name */
1490
1491 if (!CHECK_LEN(header, p, plen, hash_len))
1492 return 0;
1493
1494 if (digest_len == base32_len && hash_len == base32_len)
1495 {
1496 int rc = memcmp(workspace2, digest, digest_len);
1497
1498 if (rc == 0)
1499 {
1500 /* We found an NSEC3 whose hashed name exactly matches the query, so
1501 we just need to check the type map. p points to the RR data for the record. */
1502
1503 int offset = (type & 0xff) >> 3;
1504 int mask = 0x80 >> (type & 0x07);
1505
1506 p += hash_len; /* skip next-domain hash */
1507 rdlen -= p - psave;
1508
1509 if (!CHECK_LEN(header, p, plen, rdlen))
1510 return 0;
1511
Simon Kelley97e618a2015-01-07 21:55:43 +00001512 /* If we can prove that there's no NS record, return that information. */
1513 if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
1514 *nons = 1;
1515
Simon Kelleyfbc52052014-12-23 15:46:08 +00001516 while (rdlen >= 2)
1517 {
1518 if (p[0] == type >> 8)
1519 {
1520 /* Does the NSEC3 say our type exists? */
1521 if (offset < p[1] && (p[offset+2] & mask) != 0)
1522 return STAT_BOGUS;
1523
1524 break; /* finshed checking */
1525 }
1526
1527 rdlen -= p[1];
1528 p += p[1];
1529 }
1530
1531 return 1;
1532 }
1533 else if (rc <= 0)
1534 {
1535 /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
1536 wrap around case, name-hash falls between NSEC3 name-hash and end */
1537 if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
1538 return 1;
1539 }
1540 else
1541 {
1542 /* wrap around case, name falls between start and next domain name */
1543 if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
1544 return 1;
1545 }
1546 }
1547 }
1548 return 0;
1549}
1550
Simon Kelley24187532014-02-24 21:46:44 +00001551static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
Simon Kelley97e618a2015-01-07 21:55:43 +00001552 char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
Simon Kelley5107ace2014-02-23 10:48:32 +00001553{
Simon Kelleya857daa2014-02-24 21:01:09 +00001554 unsigned char *salt, *p, *digest;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001555 int digest_len, i, iterations, salt_len, base32_len, algo = 0;
Simon Kelley5107ace2014-02-23 10:48:32 +00001556 struct nettle_hash const *hash;
1557 char *closest_encloser, *next_closest, *wildcard;
Simon Kelley97e618a2015-01-07 21:55:43 +00001558
1559 if (nons)
1560 *nons = 0;
1561
Simon Kelley5107ace2014-02-23 10:48:32 +00001562 /* Look though the NSEC3 records to find the first one with
1563 an algorithm we support (currently only algo == 1).
1564
1565 Take the algo, iterations, and salt of that record
1566 as the ones we're going to use, and prune any
1567 that don't match. */
1568
1569 for (i = 0; i < nsec_count; i++)
1570 {
1571 if (!(p = skip_name(nsecs[i], header, plen, 15)))
Simon Kelley87070192014-03-01 20:48:24 +00001572 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001573
1574 p += 10; /* type, class, TTL, rdlen */
1575 algo = *p++;
1576
1577 if (algo == 1)
1578 break; /* known algo */
1579 }
1580
1581 /* No usable NSEC3s */
1582 if (i == nsec_count)
1583 return STAT_BOGUS;
1584
1585 p++; /* flags */
1586 GETSHORT (iterations, p);
1587 salt_len = *p++;
1588 salt = p;
1589 if (!CHECK_LEN(header, salt, plen, salt_len))
Simon Kelley87070192014-03-01 20:48:24 +00001590 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001591
1592 /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
1593 for (i = 0; i < nsec_count; i++)
1594 {
1595 unsigned char *nsec3p = nsecs[i];
1596 int this_iter;
1597
1598 nsecs[i] = NULL; /* Speculative, will be restored if OK. */
1599
1600 if (!(p = skip_name(nsec3p, header, plen, 15)))
Simon Kelley87070192014-03-01 20:48:24 +00001601 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001602
1603 p += 10; /* type, class, TTL, rdlen */
1604
1605 if (*p++ != algo)
1606 continue;
1607
1608 p++; /* flags */
1609
Simon Kelleya857daa2014-02-24 21:01:09 +00001610 GETSHORT(this_iter, p);
Simon Kelley5107ace2014-02-23 10:48:32 +00001611 if (this_iter != iterations)
1612 continue;
1613
1614 if (salt_len != *p++)
1615 continue;
1616
1617 if (!CHECK_LEN(header, p, plen, salt_len))
Simon Kelley87070192014-03-01 20:48:24 +00001618 return STAT_BOGUS; /* bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001619
1620 if (memcmp(p, salt, salt_len) != 0)
1621 continue;
1622
1623 /* All match, put the pointer back */
1624 nsecs[i] = nsec3p;
1625 }
1626
1627 /* Algo is checked as 1 above */
1628 if (!(hash = hash_find("sha1")))
Simon Kelley87070192014-03-01 20:48:24 +00001629 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001630
Simon Kelleyfbc52052014-12-23 15:46:08 +00001631 if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
1632 return STAT_BOGUS;
1633
Simon Kelley97e618a2015-01-07 21:55:43 +00001634 if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
Simon Kelleyfbc52052014-12-23 15:46:08 +00001635 return STAT_SECURE;
1636
1637 /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
1638 or an answer inferred from a wildcard record. */
Simon Kelley5107ace2014-02-23 10:48:32 +00001639 closest_encloser = name;
1640 next_closest = NULL;
1641
1642 do
1643 {
1644 if (*closest_encloser == '.')
1645 closest_encloser++;
1646
Simon Kelleyfbc52052014-12-23 15:46:08 +00001647 if (wildname && hostname_isequal(closest_encloser, wildname))
1648 break;
1649
Simon Kelleya857daa2014-02-24 21:01:09 +00001650 if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelley87070192014-03-01 20:48:24 +00001651 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001652
1653 for (i = 0; i < nsec_count; i++)
1654 if ((p = nsecs[i]))
1655 {
Simon Kelley5107ace2014-02-23 10:48:32 +00001656 if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
Simon Kelleya857daa2014-02-24 21:01:09 +00001657 !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
Simon Kelley87070192014-03-01 20:48:24 +00001658 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001659
Simon Kelleya857daa2014-02-24 21:01:09 +00001660 if (digest_len == base32_len &&
1661 memcmp(digest, workspace2, digest_len) == 0)
Simon Kelley5107ace2014-02-23 10:48:32 +00001662 break; /* Gotit */
1663 }
1664
1665 if (i != nsec_count)
1666 break;
1667
1668 next_closest = closest_encloser;
1669 }
1670 while ((closest_encloser = strchr(closest_encloser, '.')));
1671
Simon Kelleyfbc52052014-12-23 15:46:08 +00001672 if (!closest_encloser)
Simon Kelley5107ace2014-02-23 10:48:32 +00001673 return STAT_BOGUS;
1674
Simon Kelley24187532014-02-24 21:46:44 +00001675 /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
Simon Kelleya857daa2014-02-24 21:01:09 +00001676 if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
Simon Kelley87070192014-03-01 20:48:24 +00001677 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001678
Simon Kelley97e618a2015-01-07 21:55:43 +00001679 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
Simon Kelleyfbc52052014-12-23 15:46:08 +00001680 return STAT_BOGUS;
Simon Kelley5107ace2014-02-23 10:48:32 +00001681
1682 /* Finally, check that there's no seat of wildcard synthesis */
Simon Kelleyfbc52052014-12-23 15:46:08 +00001683 if (!wildname)
1684 {
1685 if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
1686 return STAT_BOGUS;
1687
1688 wildcard--;
1689 *wildcard = '*';
1690
1691 if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
1692 return STAT_BOGUS;
1693
Simon Kelley97e618a2015-01-07 21:55:43 +00001694 if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
Simon Kelleyfbc52052014-12-23 15:46:08 +00001695 return STAT_BOGUS;
1696 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001697
Simon Kelleyfbc52052014-12-23 15:46:08 +00001698 return STAT_SECURE;
Simon Kelley5107ace2014-02-23 10:48:32 +00001699}
1700
Simon Kelley0fc2f312014-01-08 10:26:58 +00001701/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001702/* Returns are the same as validate_rrset, plus the class if the missing key is in *class */
Simon Kelley97e618a2015-01-07 21:55:43 +00001703int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
1704 int *class, int *neganswer, int *nons)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001705{
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001706 unsigned char *ans_start, *qname, *p1, *p2, **nsecs;
1707 int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype;
Simon Kelley1fbe4d22014-03-01 20:03:47 +00001708 int i, j, rc, nsec_count, cname_count = CNAME_CHAIN;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001709 int nsec_type = 0, have_answer = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001710
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001711 if (neganswer)
1712 *neganswer = 0;
1713
Simon Kelley87070192014-03-01 20:48:24 +00001714 if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001715 return STAT_BOGUS;
1716
Simon Kelley87070192014-03-01 20:48:24 +00001717 if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001718 return STAT_INSECURE;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001719
1720 qname = p1 = (unsigned char *)(header+1);
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001721
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001722 if (!extract_name(header, plen, &p1, name, 1, 4))
Simon Kelley87070192014-03-01 20:48:24 +00001723 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001724
1725 GETSHORT(qtype, p1);
1726 GETSHORT(qclass, p1);
1727 ans_start = p1;
Simon Kelley9d1b22a2014-04-29 13:02:41 +01001728
1729 if (qtype == T_ANY)
1730 have_answer = 1;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001731
1732 /* Can't validate an RRISG query */
1733 if (qtype == T_RRSIG)
1734 return STAT_INSECURE;
1735
1736 cname_loop:
1737 for (j = ntohs(header->ancount); j != 0; j--)
1738 {
1739 /* leave pointer to missing name in qname */
1740
1741 if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001742 return STAT_BOGUS; /* bad packet */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001743
1744 GETSHORT(type2, p1);
1745 GETSHORT(class2, p1);
1746 p1 += 4; /* TTL */
1747 GETSHORT(rdlen2, p1);
1748
1749 if (rc == 1 && qclass == class2)
1750 {
1751 /* Do we have an answer for the question? */
1752 if (type2 == qtype)
1753 {
1754 have_answer = 1;
1755 break;
1756 }
1757 else if (type2 == T_CNAME)
1758 {
1759 qname = p1;
1760
1761 /* looped CNAMES */
1762 if (!cname_count-- || !extract_name(header, plen, &p1, name, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +00001763 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001764
1765 p1 = ans_start;
1766 goto cname_loop;
1767 }
1768 }
1769
1770 if (!ADD_RDLEN(header, p1, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001771 return STAT_BOGUS;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001772 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001773
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001774 if (neganswer && !have_answer)
1775 *neganswer = 1;
Simon Kelley05756102014-03-01 18:07:57 +00001776
1777 /* No data, therefore no sigs */
1778 if (ntohs(header->ancount) + ntohs(header->nscount) == 0)
1779 return STAT_NO_SIG;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001780
Simon Kelley0fc2f312014-01-08 10:26:58 +00001781 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001782 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001783 if (!extract_name(header, plen, &p1, name, 1, 10))
Simon Kelley87070192014-03-01 20:48:24 +00001784 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001785
1786 GETSHORT(type1, p1);
1787 GETSHORT(class1, p1);
1788 p1 += 4; /* TTL */
1789 GETSHORT(rdlen1, p1);
1790
1791 /* Don't try and validate RRSIGs! */
1792 if (type1 != T_RRSIG)
1793 {
1794 /* Check if we've done this RRset already */
1795 for (p2 = ans_start, j = 0; j < i; j++)
1796 {
1797 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001798 return STAT_BOGUS; /* bad packet */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001799
1800 GETSHORT(type2, p2);
1801 GETSHORT(class2, p2);
1802 p2 += 4; /* TTL */
1803 GETSHORT(rdlen2, p2);
1804
1805 if (type2 == type1 && class2 == class1 && rc == 1)
1806 break; /* Done it before: name, type, class all match. */
1807
1808 if (!ADD_RDLEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001809 return STAT_BOGUS;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001810 }
1811
1812 /* Not done, validate now */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001813 if (j == i)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001814 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001815 int ttl, keytag, algo, digest, type_covered;
1816 unsigned char *psave;
1817 struct all_addr a;
1818 struct blockdata *key;
1819 struct crec *crecp;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001820 char *wildname;
Simon Kelley5e321732015-01-12 23:16:56 +00001821 int have_wildcard = 0;
Simon Kelleyfbc52052014-12-23 15:46:08 +00001822
1823 rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
Simon Kelley5107ace2014-02-23 10:48:32 +00001824
1825 if (rc == STAT_SECURE_WILDCARD)
1826 {
Simon Kelley5e321732015-01-12 23:16:56 +00001827 have_wildcard = 1;
1828
Simon Kelley5107ace2014-02-23 10:48:32 +00001829 /* An attacker replay a wildcard answer with a different
Simon Kelleya857daa2014-02-24 21:01:09 +00001830 answer and overlay a genuine RR. To prove this
Simon Kelley5107ace2014-02-23 10:48:32 +00001831 hasn't happened, the answer must prove that
Simon Kelleya857daa2014-02-24 21:01:09 +00001832 the gennuine record doesn't exist. Check that here. */
Simon Kelley87070192014-03-01 20:48:24 +00001833 if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
1834 return STAT_BOGUS; /* No NSECs or bad packet */
Simon Kelley5107ace2014-02-23 10:48:32 +00001835
1836 if (nsec_type == T_NSEC)
Simon Kelley97e618a2015-01-07 21:55:43 +00001837 rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
Simon Kelley5107ace2014-02-23 10:48:32 +00001838 else
Simon Kelley97e618a2015-01-07 21:55:43 +00001839 rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename,
1840 keyname, name, type1, wildname, NULL);
1841
Simon Kelley5107ace2014-02-23 10:48:32 +00001842 if (rc != STAT_SECURE)
1843 return rc;
1844 }
1845 else if (rc != STAT_SECURE)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001846 {
1847 if (class)
1848 *class = class1; /* Class for DS or DNSKEY */
1849 return rc;
1850 }
Simon Kelley5107ace2014-02-23 10:48:32 +00001851
Simon Kelley8d718cb2014-02-03 16:27:37 +00001852 /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
1853 cache_start_insert();
1854
1855 for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001856 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001857 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
Simon Kelley87070192014-03-01 20:48:24 +00001858 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001859
1860 GETSHORT(type2, p2);
1861 GETSHORT(class2, p2);
1862 GETLONG(ttl, p2);
1863 GETSHORT(rdlen2, p2);
1864
1865 if (!CHECK_LEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001866 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001867
Simon Kelley8d718cb2014-02-03 16:27:37 +00001868 if (class2 == class1 && rc == 1)
1869 {
1870 psave = p2;
1871
1872 if (type1 == T_DS && type2 == T_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001873 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001874 if (rdlen2 < 4)
Simon Kelley87070192014-03-01 20:48:24 +00001875 return STAT_BOGUS; /* bad packet */
Simon Kelley8d718cb2014-02-03 16:27:37 +00001876
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001877 GETSHORT(keytag, p2);
1878 algo = *p2++;
1879 digest = *p2++;
1880
1881 /* Cache needs to known class for DNSSEC stuff */
1882 a.addr.dnssec.class = class2;
1883
Simon Kelley8d718cb2014-02-03 16:27:37 +00001884 if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001885 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001886 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
1887 blockdata_free(key);
1888 else
1889 {
1890 a.addr.keytag = keytag;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001891 log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
Simon Kelley8d718cb2014-02-03 16:27:37 +00001892 crecp->addr.ds.digest = digest;
1893 crecp->addr.ds.keydata = key;
1894 crecp->addr.ds.algo = algo;
1895 crecp->addr.ds.keytag = keytag;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001896 crecp->addr.ds.keylen = rdlen2 - 4;
1897 }
1898 }
1899 }
1900 else if (type2 == T_RRSIG)
1901 {
1902 if (rdlen2 < 18)
Simon Kelley87070192014-03-01 20:48:24 +00001903 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001904
Simon Kelley8d718cb2014-02-03 16:27:37 +00001905 GETSHORT(type_covered, p2);
1906
1907 if (type_covered == type1 &&
1908 (type_covered == T_A || type_covered == T_AAAA ||
1909 type_covered == T_CNAME || type_covered == T_DS ||
1910 type_covered == T_DNSKEY || type_covered == T_PTR))
1911 {
1912 a.addr.dnssec.type = type_covered;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001913 a.addr.dnssec.class = class1;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001914
1915 algo = *p2++;
1916 p2 += 13; /* labels, orig_ttl, expiration, inception */
1917 GETSHORT(keytag, p2);
1918
Simon Kelley5e321732015-01-12 23:16:56 +00001919 /* We don't cache sigs for wildcard answers, because to reproduce the
1920 answer from the cache will require one or more NSEC/NSEC3 records
1921 which we don't cache. The lack of the RRSIG ensures that a query for
1922 this RRset asking for a secure answer will always be forwarded. */
1923 if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
Simon Kelley8d718cb2014-02-03 16:27:37 +00001924 {
1925 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
1926 blockdata_free(key);
1927 else
1928 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001929 crecp->addr.sig.keydata = key;
1930 crecp->addr.sig.keylen = rdlen2;
1931 crecp->addr.sig.keytag = keytag;
1932 crecp->addr.sig.type_covered = type_covered;
1933 crecp->addr.sig.algo = algo;
1934 }
1935 }
1936 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001937 }
1938
Simon Kelley8d718cb2014-02-03 16:27:37 +00001939 p2 = psave;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001940 }
1941
Simon Kelley8d718cb2014-02-03 16:27:37 +00001942 if (!ADD_RDLEN(header, p2, plen, rdlen2))
Simon Kelley87070192014-03-01 20:48:24 +00001943 return STAT_BOGUS; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001944 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001945
1946 cache_end_insert();
Simon Kelley0fc2f312014-01-08 10:26:58 +00001947 }
1948 }
1949
1950 if (!ADD_RDLEN(header, p1, plen, rdlen1))
Simon Kelley87070192014-03-01 20:48:24 +00001951 return STAT_BOGUS;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001952 }
1953
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001954 /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001955 if (have_answer)
1956 return STAT_SECURE;
1957
Simon Kelley5107ace2014-02-23 10:48:32 +00001958 /* NXDOMAIN or NODATA reply, prove that (name, class1, type1) can't exist */
Simon Kelley5107ace2014-02-23 10:48:32 +00001959 /* First marshall the NSEC records, if we've not done it previously */
Simon Kelley87070192014-03-01 20:48:24 +00001960 if (!nsec_type && !(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
1961 return STAT_BOGUS; /* No NSECs */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001962
1963 /* Get name of missing answer */
1964 if (!extract_name(header, plen, &qname, name, 1, 0))
Simon Kelley87070192014-03-01 20:48:24 +00001965 return STAT_BOGUS;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001966
Simon Kelley5107ace2014-02-23 10:48:32 +00001967 if (nsec_type == T_NSEC)
Simon Kelley97e618a2015-01-07 21:55:43 +00001968 return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
Simon Kelley5107ace2014-02-23 10:48:32 +00001969 else
Simon Kelley97e618a2015-01-07 21:55:43 +00001970 return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
Giovanni Bajoadca3e92012-04-25 17:46:53 +02001971}
1972
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001973/* Chase the CNAME chain in the packet until the first record which _doesn't validate.
1974 Needed for proving answer in unsigned space.
1975 Return STAT_NEED_*
1976 STAT_BOGUS - error
1977 STAT_INSECURE - name of first non-secure record in name
1978*/
1979int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
1980{
1981 unsigned char *p = (unsigned char *)(header+1);
Simon Kelleyc07d30d2014-03-03 14:19:19 +00001982 int type, class, qclass, rdlen, j, rc;
Simon Kelley1fbe4d22014-03-01 20:03:47 +00001983 int cname_count = CNAME_CHAIN;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001984
1985 /* Get question */
1986 if (!extract_name(header, plen, &p, name, 1, 4))
1987 return STAT_BOGUS;
1988
Simon Kelleyc07d30d2014-03-03 14:19:19 +00001989 p +=2; /* type */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001990 GETSHORT(qclass, p);
1991
1992 while (1)
1993 {
1994 for (j = ntohs(header->ancount); j != 0; j--)
1995 {
1996 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
1997 return STAT_BOGUS; /* bad packet */
1998
1999 GETSHORT(type, p);
2000 GETSHORT(class, p);
2001 p += 4; /* TTL */
2002 GETSHORT(rdlen, p);
2003
2004 /* Not target, loop */
2005 if (rc == 2 || qclass != class)
2006 {
2007 if (!ADD_RDLEN(header, p, plen, rdlen))
2008 return STAT_BOGUS;
2009 continue;
2010 }
2011
2012 /* Got to end of CNAME chain. */
2013 if (type != T_CNAME)
2014 return STAT_INSECURE;
2015
2016 /* validate CNAME chain, return if insecure or need more data */
Simon Kelleyfbc52052014-12-23 15:46:08 +00002017 rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, NULL, 0, 0, 0);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002018 if (rc != STAT_SECURE)
2019 {
2020 if (rc == STAT_NO_SIG)
2021 rc = STAT_INSECURE;
2022 return rc;
2023 }
2024
2025 /* Loop down CNAME chain/ */
2026 if (!cname_count-- ||
2027 !extract_name(header, plen, &p, name, 1, 0) ||
2028 !(p = skip_questions(header, plen)))
2029 return STAT_BOGUS;
2030
2031 break;
2032 }
2033
2034 /* End of CNAME chain */
2035 return STAT_INSECURE;
2036 }
2037}
2038
2039
Giovanni Bajo3471f182012-04-25 17:49:16 +02002040/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002041int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02002042{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002043 if (alg == 1)
2044 {
2045 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
2046 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00002047 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002048 }
2049 else
2050 {
Simon Kelley1633e302014-02-10 16:42:46 +00002051 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002052 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02002053
Simon Kelley0fc2f312014-01-08 10:26:58 +00002054 for (i = 0; i < keylen; ++i)
2055 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00002056
Simon Kelley0fc2f312014-01-08 10:26:58 +00002057 ac += (ac >> 16) & 0xffff;
2058 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02002059 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02002060}
2061
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002062size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr)
2063{
2064 unsigned char *p;
Simon Kelley610e7822014-02-06 14:45:17 +00002065 char *types = querystr("dnssec-query", type);
Giovanni Bajo0304d282012-05-02 03:29:52 +02002066
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002067 if (addr->sa.sa_family == AF_INET)
Simon Kelley25cf5e32015-01-09 15:53:03 +00002068 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002069#ifdef HAVE_IPV6
2070 else
Simon Kelley25cf5e32015-01-09 15:53:03 +00002071 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002072#endif
2073
2074 header->qdcount = htons(1);
2075 header->ancount = htons(0);
2076 header->nscount = htons(0);
2077 header->arcount = htons(0);
2078
2079 header->hb3 = HB3_RD;
2080 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00002081 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2082 this allows it to select auth servers when one is returning bad data. */
2083 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002084
2085 /* ID filled in later */
2086
2087 p = (unsigned char *)(header+1);
2088
2089 p = do_rfc1035_name(p, name);
2090 *p++ = 0;
2091 PUTSHORT(type, p);
2092 PUTSHORT(class, p);
2093
2094 return add_do_bit(header, p - (unsigned char *)header, end);
2095}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002096
Simon Kelley613ad152014-02-25 23:02:28 +00002097/* Go through a domain name, find "pointers" and fix them up based on how many bytes
2098 we've chopped out of the packet, or check they don't point into an elided part. */
2099static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
2100{
2101 unsigned char *ansp = *namep;
2102
2103 while(1)
2104 {
2105 unsigned int label_type;
2106
2107 if (!CHECK_LEN(header, ansp, plen, 1))
2108 return 0;
2109
2110 label_type = (*ansp) & 0xc0;
2111
2112 if (label_type == 0xc0)
2113 {
2114 /* pointer for compression. */
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002115 unsigned int offset;
2116 int i;
Simon Kelley613ad152014-02-25 23:02:28 +00002117 unsigned char *p;
2118
2119 if (!CHECK_LEN(header, ansp, plen, 2))
2120 return 0;
2121
2122 offset = ((*ansp++) & 0x3f) << 8;
2123 offset |= *ansp++;
2124
2125 p = offset + (unsigned char *)header;
2126
2127 for (i = 0; i < rr_count; i++)
2128 if (p < rrs[i])
2129 break;
2130 else
2131 if (i & 1)
2132 offset -= rrs[i] - rrs[i-1];
2133
2134 /* does the pointer end up in an elided RR? */
2135 if (i & 1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002136 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +00002137
2138 /* No, scale the pointer */
2139 if (fixup)
2140 {
2141 ansp -= 2;
2142 *ansp++ = (offset >> 8) | 0xc0;
2143 *ansp++ = offset & 0xff;
2144 }
2145 break;
2146 }
2147 else if (label_type == 0x80)
2148 return 0; /* reserved */
2149 else if (label_type == 0x40)
2150 {
2151 /* Extended label type */
2152 unsigned int count;
2153
2154 if (!CHECK_LEN(header, ansp, plen, 2))
2155 return 0;
2156
2157 if (((*ansp++) & 0x3f) != 1)
2158 return 0; /* we only understand bitstrings */
2159
2160 count = *(ansp++); /* Bits in bitstring */
2161
2162 if (count == 0) /* count == 0 means 256 bits */
2163 ansp += 32;
2164 else
2165 ansp += ((count-1)>>3)+1;
2166 }
2167 else
2168 { /* label type == 0 Bottom six bits is length */
2169 unsigned int len = (*ansp++) & 0x3f;
2170
2171 if (!ADD_RDLEN(header, ansp, plen, len))
2172 return 0;
2173
2174 if (len == 0)
2175 break; /* zero length label marks the end. */
2176 }
2177 }
2178
2179 *namep = ansp;
2180
2181 return 1;
2182}
2183
2184/* Go through RRs and check or fixup the domain names contained within */
2185static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
2186{
2187 int i, type, class, rdlen;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002188 unsigned char *pp;
Simon Kelley613ad152014-02-25 23:02:28 +00002189
Simon Kelley50f86ce2014-04-24 17:59:58 +01002190 for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
Simon Kelley613ad152014-02-25 23:02:28 +00002191 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002192 pp = p;
2193
2194 if (!(p = skip_name(p, header, plen, 10)))
2195 return 0;
Simon Kelley613ad152014-02-25 23:02:28 +00002196
2197 GETSHORT(type, p);
2198 GETSHORT(class, p);
2199 p += 4; /* TTL */
2200 GETSHORT(rdlen, p);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002201
Simon Kelley613ad152014-02-25 23:02:28 +00002202 if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
2203 {
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002204 /* fixup name of RR */
2205 if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
2206 return 0;
2207
Simon Kelley613ad152014-02-25 23:02:28 +00002208 if (class == C_IN)
2209 {
2210 u16 *d;
Simon Kelley14db4212014-03-01 15:35:50 +00002211
2212 for (pp = p, d = get_desc(type); *d != (u16)-1; d++)
Simon Kelley613ad152014-02-25 23:02:28 +00002213 {
2214 if (*d != 0)
2215 pp += *d;
2216 else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
2217 return 0;
2218 }
2219 }
2220 }
2221
2222 if (!ADD_RDLEN(header, p, plen, rdlen))
2223 return 0;
2224 }
2225
2226 return 1;
2227}
2228
2229
2230size_t filter_rrsigs(struct dns_header *header, size_t plen)
2231{
2232 static unsigned char **rrs;
2233 static int rr_sz = 0;
2234
2235 unsigned char *p = (unsigned char *)(header+1);
Simon Kelley50f86ce2014-04-24 17:59:58 +01002236 int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
Simon Kelley613ad152014-02-25 23:02:28 +00002237
2238 if (ntohs(header->qdcount) != 1 ||
2239 !(p = skip_name(p, header, plen, 4)))
2240 return plen;
2241
2242 GETSHORT(qtype, p);
2243 GETSHORT(qclass, p);
2244
2245 /* First pass, find pointers to start and end of all the records we wish to elide:
2246 records added for DNSSEC, unless explicity queried for */
Simon Kelley50f86ce2014-04-24 17:59:58 +01002247 for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
2248 i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
2249 i++)
Simon Kelley613ad152014-02-25 23:02:28 +00002250 {
2251 unsigned char *pstart = p;
2252 int type, class;
2253
2254 if (!(p = skip_name(p, header, plen, 10)))
2255 return plen;
2256
2257 GETSHORT(type, p);
2258 GETSHORT(class, p);
2259 p += 4; /* TTL */
2260 GETSHORT(rdlen, p);
2261
2262 if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) &&
2263 (type != qtype || class != qclass))
2264 {
2265 if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
2266 return plen;
2267
2268 rrs[rr_found++] = pstart;
2269
2270 if (!ADD_RDLEN(header, p, plen, rdlen))
2271 return plen;
2272
2273 rrs[rr_found++] = p;
2274
2275 if (i < ntohs(header->ancount))
2276 chop_an++;
Simon Kelleye6096e62014-05-01 18:19:12 +01002277 else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
Simon Kelley613ad152014-02-25 23:02:28 +00002278 chop_ns++;
Simon Kelley50f86ce2014-04-24 17:59:58 +01002279 else
2280 chop_ar++;
Simon Kelley613ad152014-02-25 23:02:28 +00002281 }
2282 else if (!ADD_RDLEN(header, p, plen, rdlen))
2283 return plen;
2284 }
2285
2286 /* Nothing to do. */
2287 if (rr_found == 0)
2288 return plen;
2289
2290 /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
2291 point to records we're going to elide. This is theoretically possible, but unlikely. If
2292 it happens, we give up and leave the answer unchanged. */
2293 p = (unsigned char *)(header+1);
2294
2295 /* question first */
2296 if (!check_name(&p, header, plen, 0, rrs, rr_found))
2297 return plen;
2298 p += 4; /* qclass, qtype */
2299
2300 /* Now answers and NS */
2301 if (!check_rrs(p, header, plen, 0, rrs, rr_found))
2302 return plen;
2303
2304 /* Third pass, elide records */
2305 for (p = rrs[0], i = 1; i < rr_found; i += 2)
2306 {
2307 unsigned char *start = rrs[i];
2308 unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
2309
2310 memmove(p, start, end-start);
2311 p += end-start;
2312 }
2313
2314 plen = p - (unsigned char *)header;
2315 header->ancount = htons(ntohs(header->ancount) - chop_an);
2316 header->nscount = htons(ntohs(header->nscount) - chop_ns);
Simon Kelley50f86ce2014-04-24 17:59:58 +01002317 header->arcount = htons(ntohs(header->arcount) - chop_ar);
2318
Simon Kelley613ad152014-02-25 23:02:28 +00002319 /* Fourth pass, fix up pointers in the remaining records */
2320 p = (unsigned char *)(header+1);
2321
2322 check_name(&p, header, plen, 1, rrs, rr_found);
2323 p += 4; /* qclass, qtype */
2324
2325 check_rrs(p, header, plen, 1, rrs, rr_found);
2326
2327 return plen;
2328}
2329
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002330unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
2331{
2332 int q;
2333 unsigned int len;
2334 unsigned char *p = (unsigned char *)(header+1);
2335 const struct nettle_hash *hash;
2336 void *ctx;
2337 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00002338
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002339 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
2340 return NULL;
2341
2342 for (q = ntohs(header->qdcount); q != 0; q--)
2343 {
2344 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00002345 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002346
2347 len = to_wire(name);
2348 hash->update(ctx, len, (unsigned char *)name);
2349 /* CRC the class and type as well */
2350 hash->update(ctx, 4, p);
2351
2352 p += 4;
2353 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00002354 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002355 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00002356
2357 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002358 return digest;
2359}
2360
Simon Kelley0fc2f312014-01-08 10:26:58 +00002361#endif /* HAVE_DNSSEC */