blob: 5511143a173d1d65a3f8a27bee2c40ae92aa52c2 [file] [log] [blame]
Giovanni Bajo8d41ebd2012-05-05 00:48:12 +02001/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
Simon Kelley0fc2f312014-01-08 10:26:58 +00002 and Copyright (c) 2012-2014 Simon Kelley
Giovanni Bajo8d41ebd2012-05-05 00:48:12 +02003
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 dated June, 1991, or
7 (at your option) version 3 dated 29 June, 2007.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
Giovanni Bajoe292e932012-04-22 14:32:02 +020017
18#include "dnsmasq.h"
Simon Kelley0fc2f312014-01-08 10:26:58 +000019
20#ifdef HAVE_DNSSEC
21
Simon Kelley86bec2d2014-01-13 21:31:20 +000022#include <nettle/rsa.h>
23#include <nettle/dsa.h>
Simon Kelleyc152dc82014-02-19 18:14:33 +000024#ifndef NO_NETTLE_ECC
25# include <nettle/ecdsa.h>
26# include <nettle/ecc-curve.h>
27#endif
Simon Kelley86bec2d2014-01-13 21:31:20 +000028#include <nettle/nettle-meta.h>
29#include <gmp.h>
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000030
Giovanni Bajoe292e932012-04-22 14:32:02 +020031#define SERIAL_UNDEF -100
32#define SERIAL_EQ 0
33#define SERIAL_LT -1
34#define SERIAL_GT 1
35
Simon Kelley86bec2d2014-01-13 21:31:20 +000036/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
37static char *ds_digest_name(int digest)
38{
39 switch (digest)
40 {
41 case 1: return "sha1";
42 case 2: return "sha256";
43 case 3: return "gosthash94";
44 case 4: return "sha384";
45 default: return NULL;
46 }
47}
48
49/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
50static char *algo_digest_name(int algo)
51{
52 switch (algo)
53 {
54 case 1: return "md5";
55 case 3: return "sha1";
56 case 5: return "sha1";
57 case 6: return "sha1";
58 case 7: return "sha1";
59 case 8: return "sha256";
60 case 10: return "sha512";
61 case 12: return "gosthash94";
62 case 13: return "sha256";
63 case 14: return "sha384";
64 default: return NULL;
65 }
66}
67
68/* Find pointer to correct hash function in nettle library */
69static const struct nettle_hash *hash_find(char *name)
70{
71 int i;
72
73 if (!name)
74 return NULL;
75
76 for (i = 0; nettle_hashes[i]; i++)
77 {
78 if (strcmp(nettle_hashes[i]->name, name) == 0)
79 return nettle_hashes[i];
80 }
81
82 return NULL;
83}
84
85/* expand ctx and digest memory allocations if necessary and init hash function */
86static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
87{
88 static void *ctx = NULL;
89 static unsigned char *digest = NULL;
90 static unsigned int ctx_sz = 0;
91 static unsigned int digest_sz = 0;
92
93 void *new;
94
95 if (ctx_sz < hash->context_size)
96 {
97 if (!(new = whine_malloc(hash->context_size)))
98 return 0;
99 if (ctx)
100 free(ctx);
101 ctx = new;
102 ctx_sz = hash->context_size;
103 }
104
105 if (digest_sz < hash->digest_size)
106 {
107 if (!(new = whine_malloc(hash->digest_size)))
108 return 0;
109 if (digest)
110 free(digest);
111 digest = new;
112 digest_sz = hash->digest_size;
113 }
114
115 *ctxp = ctx;
116 *digestp = digest;
117
118 hash->init(ctx);
119
120 return 1;
121}
122
123static int rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
124 unsigned char *digest, int algo)
125{
126 unsigned char *p;
127 size_t exp_len;
128
129 static struct rsa_public_key *key = NULL;
130 static mpz_t sig_mpz;
131
132 if (key == NULL)
133 {
134 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
135 return 0;
136
137 nettle_rsa_public_key_init(key);
138 mpz_init(sig_mpz);
139 }
140
141 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
142 return 0;
143
144 key_len--;
145 if ((exp_len = *p++) == 0)
146 {
147 GETSHORT(exp_len, p);
148 key_len -= 2;
149 }
150
151 if (exp_len >= key_len)
152 return 0;
153
154 key->size = key_len - exp_len;
155 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
156 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
157
158 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
159
160 switch (algo)
161 {
162 case 1:
163 return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
164 case 5: case 7:
165 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
166 case 8:
167 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
168 case 10:
169 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
170 }
171
172 return 0;
173}
174
175static int dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
176 unsigned char *digest, int algo)
177{
178 unsigned char *p;
179 unsigned int t;
180
181 static struct dsa_public_key *key = NULL;
182 static struct dsa_signature *sig_struct;
183
184 if (key == NULL)
185 {
186 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
187 !(key = whine_malloc(sizeof(struct dsa_public_key))))
188 return 0;
189
190 nettle_dsa_public_key_init(key);
191 nettle_dsa_signature_init(sig_struct);
192 }
193
194 if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
195 return 0;
196
197 t = *p++;
198
199 if (key_len < (213 + (t * 24)))
200 return 0;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000201
Simon Kelley86bec2d2014-01-13 21:31:20 +0000202 mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
203 mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
204 mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
205 mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
206
207 mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
208 mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
209
210 (void)algo;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000211
Simon Kelley86bec2d2014-01-13 21:31:20 +0000212 return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
213}
214
Simon Kelleyc152dc82014-02-19 18:14:33 +0000215#ifndef NO_NETTLE_ECC
216static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
217 unsigned char *sig, size_t sig_len,
Simon Kelleyebe95a82014-02-13 14:56:10 +0000218 unsigned char *digest, size_t digest_len, int algo)
219{
220 unsigned char *p;
221 unsigned int t;
222 struct ecc_point *key;
223
224 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
225 static mpz_t x, y;
226 static struct dsa_signature *sig_struct;
227
228 if (!sig_struct)
229 {
230 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
231 return 0;
232
233 nettle_dsa_signature_init(sig_struct);
234 mpz_init(x);
235 mpz_init(y);
236 }
237
238 switch (algo)
239 {
240 case 13:
241 if (!key_256)
242 {
243 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
244 return 0;
245
246 nettle_ecc_point_init(key_256, &nettle_secp_256r1);
247 }
248
249 key = key_256;
250 t = 32;
251 break;
252
253 case 14:
254 if (!key_384)
255 {
256 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
257 return 0;
258
259 nettle_ecc_point_init(key_384, &nettle_secp_384r1);
260 }
261
262 key = key_384;
263 t = 48;
264 break;
265
266 default:
267 return 0;
268 }
269
270 if (sig_len != 2*t || key_len != 2*t ||
271 (p = blockdata_retrieve(key_data, key_len, NULL)))
272 return 0;
273
274 mpz_import(x, t , 1, 1, 0, 0, p);
275 mpz_import(y, t , 1, 1, 0, 0, p + t);
276
277 if (!ecc_point_set(key, x, y))
278 return 0;
279
280 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
281 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
282
283 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
284}
Simon Kelleyc152dc82014-02-19 18:14:33 +0000285#endif
286
Simon Kelley86bec2d2014-01-13 21:31:20 +0000287static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
Simon Kelleyebe95a82014-02-13 14:56:10 +0000288 unsigned char *digest, size_t digest_len, int algo)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000289{
290 switch (algo)
291 {
292 case 1: case 5: case 7: case 8: case 10:
293 return rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
294
295 case 3: case 6:
296 return dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
Simon Kelleyc152dc82014-02-19 18:14:33 +0000297
298#ifndef NO_NETTLE_ECC
Simon Kelleyebe95a82014-02-13 14:56:10 +0000299 case 13: case 14:
300 return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
Simon Kelleyc152dc82014-02-19 18:14:33 +0000301#endif
302 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000303
304 return 0;
305}
306
Simon Kelley0fc2f312014-01-08 10:26:58 +0000307/* Convert from presentation format to wire format, in place.
308 Also map UC -> LC.
309 Note that using extract_name to get presentation format
310 then calling to_wire() removes compression and maps case,
311 thus generating names in canonical form.
312 Calling to_wire followed by from_wire is almost an identity,
313 except that the UC remains mapped to LC.
314*/
315static int to_wire(char *name)
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200316{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000317 unsigned char *l, *p, term;
318 int len;
319
320 for (l = (unsigned char*)name; *l != 0; l = p)
321 {
322 for (p = l; *p != '.' && *p != 0; p++)
323 if (*p >= 'A' && *p <= 'Z')
324 *p = *p - 'A' + 'a';
325
326 term = *p;
327
328 if ((len = p - l) != 0)
329 memmove(l+1, l, len);
330 *l = len;
331
332 p++;
333
334 if (term == 0)
335 *p = 0;
336 }
337
338 return l + 1 - (unsigned char *)name;
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200339}
340
Simon Kelley0fc2f312014-01-08 10:26:58 +0000341/* Note: no compression allowed in input. */
342static void from_wire(char *name)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200343{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000344 unsigned char *l;
345 int len;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200346
Simon Kelley0fc2f312014-01-08 10:26:58 +0000347 for (l = (unsigned char *)name; *l != 0; l += len+1)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200348 {
Simon Kelley0fc2f312014-01-08 10:26:58 +0000349 len = *l;
350 memmove(l, l+1, len);
351 l[len] = '.';
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200352 }
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200353
Simon Kelley0fc2f312014-01-08 10:26:58 +0000354 *(l-1) = 0;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200355}
356
Simon Kelley5ada8882014-01-09 22:25:03 +0000357/* Input in presentation format */
358static int count_labels(char *name)
359{
360 int i;
361
362 if (*name == 0)
363 return 0;
364
365 for (i = 0; *name; name++)
366 if (*name == '.')
367 i++;
368
369 return i+1;
370}
371
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000372/* Implement RFC1982 wrapped compare for 32-bit numbers */
373static int serial_compare_32(unsigned long s1, unsigned long s2)
Giovanni Bajo0852d762012-04-28 03:49:24 +0200374{
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000375 if (s1 == s2)
376 return SERIAL_EQ;
Giovanni Bajo0852d762012-04-28 03:49:24 +0200377
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000378 if ((s1 < s2 && (s2 - s1) < (1UL<<31)) ||
379 (s1 > s2 && (s1 - s2) > (1UL<<31)))
380 return SERIAL_LT;
381 if ((s1 < s2 && (s2 - s1) > (1UL<<31)) ||
382 (s1 > s2 && (s1 - s2) < (1UL<<31)))
383 return SERIAL_GT;
384 return SERIAL_UNDEF;
385}
Giovanni Bajo0852d762012-04-28 03:49:24 +0200386
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000387/* Check whether today/now is between date_start and date_end */
388static int check_date_range(unsigned long date_start, unsigned long date_end)
389{
390 unsigned long curtime = time(0);
391
392 /* We must explicitly check against wanted values, because of SERIAL_UNDEF */
393 return serial_compare_32(curtime, date_start) == SERIAL_GT
394 && serial_compare_32(curtime, date_end) == SERIAL_LT;
395}
396
397static u16 *get_desc(int type)
398{
399 /* List of RRtypes which include domains in the data.
400 0 -> domain
401 integer -> no of plain bytes
402 -1 -> end
403
404 zero is not a valid RRtype, so the final entry is returned for
405 anything which needs no mangling.
406 */
407
408 static u16 rr_desc[] =
409 {
410 T_NS, 0, -1,
411 T_MD, 0, -1,
412 T_MF, 0, -1,
413 T_CNAME, 0, -1,
414 T_SOA, 0, 0, -1,
415 T_MB, 0, -1,
416 T_MG, 0, -1,
417 T_MR, 0, -1,
418 T_PTR, 0, -1,
419 T_MINFO, 0, 0, -1,
420 T_MX, 2, 0, -1,
421 T_RP, 0, 0, -1,
422 T_AFSDB, 2, 0, -1,
423 T_RT, 2, 0, -1,
424 T_SIG, 18, 0, -1,
425 T_PX, 2, 0, 0, -1,
426 T_NXT, 0, -1,
427 T_KX, 2, 0, -1,
428 T_SRV, 6, 0, -1,
429 T_DNAME, 0, -1,
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000430 0, -1 /* wildcard/catchall */
431 };
432
433 u16 *p = rr_desc;
434
435 while (*p != type && *p != 0)
436 while (*p++ != (u16)-1);
437
438 return p+1;
439}
440
441/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
442 data, pointed to by *p, should be used raw. */
443static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff,
444 unsigned char **p, u16 **desc)
445{
446 int d = **desc;
447
448 (*desc)++;
449
450 /* No more data needs mangling */
451 if (d == (u16)-1)
Giovanni Bajof119ed32012-05-02 00:31:55 +0200452 return 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000453
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000454 if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
455 /* domain-name, canonicalise */
456 return to_wire(buff);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000457 else
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000458 {
459 /* plain data preceding a domain-name, don't run off the end of the data */
460 if ((end - *p) < d)
461 d = end - *p;
462
463 if (d != 0)
464 {
465 memcpy(buff, *p, d);
466 *p += d;
467 }
468
469 return d;
470 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000471}
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000472
473/* Bubble sort the RRset into the canonical order.
474 Note that the byte-streams from two RRs may get unsynced: consider
475 RRs which have two domain-names at the start and then other data.
476 The domain-names may have different lengths in each RR, but sort equal
477
478 ------------
479 |abcde|fghi|
480 ------------
481 |abcd|efghi|
482 ------------
483
484 leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
485*/
486
487static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
488 unsigned char **rrset, char *buff1, char *buff2)
489{
490 int swap, quit, i;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000491
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000492 do
493 {
494 for (swap = 0, i = 0; i < rrsetidx-1; i++)
495 {
496 int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
497 u16 *dp1, *dp2;
498 unsigned char *end1, *end2;
499 unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
500 unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
501
502 p1 += 8; /* skip class, type, ttl */
503 GETSHORT(rdlen1, p1);
504 end1 = p1 + rdlen1;
505
506 p2 += 8; /* skip class, type, ttl */
507 GETSHORT(rdlen2, p2);
508 end2 = p2 + rdlen2;
509
510 dp1 = dp2 = rr_desc;
511
Simon Kelley1486a9c2014-01-10 11:39:14 +0000512 for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000513 {
Simon Kelley1486a9c2014-01-10 11:39:14 +0000514 if (left1 != 0)
515 memmove(buff1, buff1 + len1 - left1, left1);
516
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000517 if ((len1 = get_rdata(header, plen, end1, buff1 + left1, &p1, &dp1)) == 0)
518 {
519 quit = 1;
520 len1 = end1 - p1;
521 memcpy(buff1 + left1, p1, len1);
522 }
523 len1 += left1;
524
Simon Kelley1486a9c2014-01-10 11:39:14 +0000525 if (left2 != 0)
526 memmove(buff2, buff2 + len2 - left2, left2);
527
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000528 if ((len2 = get_rdata(header, plen, end2, buff2 + left2, &p2, &dp2)) == 0)
529 {
530 quit = 1;
531 len2 = end2 - p2;
532 memcpy(buff2 + left2, p2, len2);
533 }
534 len2 += left2;
535
536 if (len1 > len2)
Simon Kelley1486a9c2014-01-10 11:39:14 +0000537 left1 = len1 - len2, left2 = 0, len = len2;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000538 else
Simon Kelley1486a9c2014-01-10 11:39:14 +0000539 left2 = len2 - len1, left1 = 0, len = len1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000540
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000541 rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000542
Simon Kelley4619d942014-01-16 19:53:06 +0000543 if (rc > 0 || (rc == 0 && quit && len1 > len2))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000544 {
545 unsigned char *tmp = rrset[i+1];
546 rrset[i+1] = rrset[i];
547 rrset[i] = tmp;
548 swap = quit = 1;
549 }
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000550 else if (rc < 0)
551 quit = 1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000552 }
553 }
554 } while (swap);
555}
556
557/* Validate a single RRset (class, type, name) in the supplied DNS reply
558 Return code:
559 STAT_SECURE if it validates.
560 STAT_INSECURE can't validate (no RRSIG, bad packet).
561 STAT_BOGUS signature is wrong.
562 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
563
564 if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
565 otherwise find the key in the cache.
566*/
567static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class,
Simon Kelleye7829ae2014-01-22 22:21:51 +0000568 int type, char *name, char *keyname, struct blockdata *key, int keylen, int algo_in, int keytag_in)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000569{
570 static unsigned char **rrset = NULL, **sigs = NULL;
571 static int rrset_sz = 0, sig_sz = 0;
572
573 unsigned char *p;
Simon Kelley5ada8882014-01-09 22:25:03 +0000574 int rrsetidx, sigidx, res, rdlen, j, name_labels;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000575 struct crec *crecp = NULL;
576 int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
577 u16 *rr_desc = get_desc(type);
578
579 if (!(p = skip_questions(header, plen)))
580 return STAT_INSECURE;
581
Simon Kelley5ada8882014-01-09 22:25:03 +0000582 name_labels = count_labels(name); /* For 4035 5.3.2 check */
583
584 /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000585 for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
586 j != 0; j--)
587 {
588 unsigned char *pstart, *pdata;
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000589 int stype, sclass;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000590
591 pstart = p;
592
593 if (!(res = extract_name(header, plen, &p, name, 0, 10)))
594 return STAT_INSECURE; /* bad packet */
595
596 GETSHORT(stype, p);
597 GETSHORT(sclass, p);
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000598 p += 4; /* TTL */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000599
600 pdata = p;
601
602 GETSHORT(rdlen, p);
603
Simon Kelleye7829ae2014-01-22 22:21:51 +0000604 if (!CHECK_LEN(header, p, plen, rdlen))
605 return STAT_INSECURE;
606
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000607 if (res == 1 && sclass == class)
608 {
609 if (stype == type)
610 {
611 if (rrsetidx == rrset_sz)
612 {
613 unsigned char **new;
614
Simon Kelleybb201c22014-02-06 12:01:05 +0000615 /* Protect against insane/maliciuos queries which bloat the workspace
616 and eat CPU in the sort */
617 if (rrsetidx >= 100)
618 return STAT_INSECURE;
619
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000620 /* expand */
621 if (!(new = whine_malloc((rrset_sz + 5) * sizeof(unsigned char **))))
622 return STAT_INSECURE;
623
624 if (rrset)
625 {
626 memcpy(new, rrset, rrset_sz * sizeof(unsigned char **));
627 free(rrset);
628 }
629
630 rrset = new;
631 rrset_sz += 5;
632 }
633 rrset[rrsetidx++] = pstart;
634 }
635
636 if (stype == T_RRSIG)
637 {
Simon Kelley5ada8882014-01-09 22:25:03 +0000638 if (rdlen < 18)
639 return STAT_INSECURE; /* bad packet */
640
641 GETSHORT(type_covered, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000642
Simon Kelleye7829ae2014-01-22 22:21:51 +0000643 if (type_covered == type)
Simon Kelley5ada8882014-01-09 22:25:03 +0000644 {
645 if (sigidx == sig_sz)
646 {
647 unsigned char **new;
648
649 /* expand */
650 if (!(new = whine_malloc((sig_sz + 5) * sizeof(unsigned char **))))
651 return STAT_INSECURE;
652
653 if (sigs)
654 {
655 memcpy(new, sigs, sig_sz * sizeof(unsigned char **));
656 free(sigs);
657 }
658
659 sigs = new;
660 sig_sz += 5;
661 }
662
663 sigs[sigidx++] = pdata;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000664 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000665 p = pdata + 2; /* restore for ADD_RDLEN */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000666 }
667 }
668
669 if (!ADD_RDLEN(header, p, plen, rdlen))
670 return STAT_INSECURE;
671 }
672
673 /* RRset empty, no RRSIGs */
674 if (rrsetidx == 0 || sigidx == 0)
675 return STAT_INSECURE;
676
677 /* Sort RRset records into canonical order.
678 Note that at this point keyname and name buffs are
679 unused, and used as workspace by the sort. */
680 sort_rrset(header, plen, rr_desc, rrsetidx, rrset, name, keyname);
681
682 /* Now try all the sigs to try and find one which validates */
683 for (j = 0; j <sigidx; j++)
684 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000685 unsigned char *psav, *sig;
686 int i, wire_len, sig_len;
687 const struct nettle_hash *hash;
688 void *ctx;
689 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000690 u32 nsigttl;
691
692 p = sigs[j];
Simon Kelley5ada8882014-01-09 22:25:03 +0000693 GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000694 psav = p;
695
Simon Kelley5ada8882014-01-09 22:25:03 +0000696 p += 2; /* type_covered - already checked */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000697 algo = *p++;
698 labels = *p++;
699 GETLONG(orig_ttl, p);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000700 GETLONG(sig_expiration, p);
701 GETLONG(sig_inception, p);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000702 GETSHORT(key_tag, p);
703
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000704 if (!extract_name(header, plen, &p, keyname, 1, 0))
705 return STAT_INSECURE;
706
Simon Kelleye7829ae2014-01-22 22:21:51 +0000707 if (!check_date_range(sig_inception, sig_expiration) ||
708 labels > name_labels ||
709 !(hash = hash_find(algo_digest_name(algo))) ||
710 !hash_init(hash, &ctx, &digest))
711 continue;
712
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000713 /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
714 if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
715 return STAT_NEED_KEY;
716
Simon Kelley86bec2d2014-01-13 21:31:20 +0000717 sig = p;
718 sig_len = rdlen - (p - psav);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000719
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000720 nsigttl = htonl(orig_ttl);
721
Simon Kelley86bec2d2014-01-13 21:31:20 +0000722 hash->update(ctx, 18, psav);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000723 wire_len = to_wire(keyname);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000724 hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000725 from_wire(keyname);
726
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000727 for (i = 0; i < rrsetidx; ++i)
728 {
729 int seg;
730 unsigned char *end, *cp;
Simon Kelley5ada8882014-01-09 22:25:03 +0000731 char *name_start = name;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000732 u16 len, *dp;
733
734 p = rrset[i];
735 if (!extract_name(header, plen, &p, name, 1, 10))
736 return STAT_INSECURE;
Simon Kelley5ada8882014-01-09 22:25:03 +0000737
738 /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
739 if (labels < name_labels)
740 {
741 int k;
742 for (k = name_labels - labels; k != 0; k--)
743 while (*name_start != '.' && *name_start != 0)
744 name_start++;
745 name_start--;
746 *name_start = '*';
747 }
748
749 wire_len = to_wire(name_start);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000750 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
751 hash->update(ctx, 4, p); /* class and type */
752 hash->update(ctx, 4, (unsigned char *)&nsigttl);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000753
754 p += 8; /* skip class, type, ttl */
755 GETSHORT(rdlen, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000756 if (!CHECK_LEN(header, p, plen, rdlen))
757 return STAT_INSECURE;
758
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000759 end = p + rdlen;
760
761 /* canonicalise rdata and calculate length of same, use name buffer as workspace */
762 cp = p;
763 dp = rr_desc;
764 for (len = 0; (seg = get_rdata(header, plen, end, name, &cp, &dp)) != 0; len += seg);
765 len += end - cp;
766 len = htons(len);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000767 hash->update(ctx, 2, (unsigned char *)&len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000768
769 /* Now canonicalise again and digest. */
770 cp = p;
771 dp = rr_desc;
772 while ((seg = get_rdata(header, plen, end, name, &cp, &dp)))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000773 hash->update(ctx, seg, (unsigned char *)name);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000774 if (cp != end)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000775 hash->update(ctx, end - cp, cp);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000776 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000777
778 hash->digest(ctx, hash->digest_size, digest);
779
Simon Kelley5ada8882014-01-09 22:25:03 +0000780 /* namebuff used for workspace above, restore to leave unchanged on exit */
781 p = (unsigned char*)(rrset[0]);
782 extract_name(header, plen, &p, name, 1, 0);
783
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000784 if (key)
785 {
786 if (algo_in == algo && keytag_in == key_tag &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000787 verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000788 return STAT_SECURE;
789 }
790 else
791 {
792 /* iterate through all possible keys 4035 5.3.1 */
793 for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000794 if (crecp->addr.key.algo == algo &&
795 crecp->addr.key.keytag == key_tag &&
Simon Kelley824202e2014-01-23 20:59:46 +0000796 crecp->uid == class &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000797 verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000798 return STAT_SECURE;
799 }
800 }
801
802 return STAT_BOGUS;
803}
804
Simon Kelley0fc2f312014-01-08 10:26:58 +0000805/* The DNS packet is expected to contain the answer to a DNSKEY query.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000806 Put all DNSKEYs in the answer which are valid into the cache.
807 return codes:
808 STAT_INSECURE bad packet, no DNSKEYs in reply.
809 STAT_SECURE At least one valid DNSKEY found and in cache.
Simon Kelley0fc2f312014-01-08 10:26:58 +0000810 STAT_BOGUS No DNSKEYs found, which can be validated with DS,
811 or self-sign for DNSKEY RRset is not valid.
812 STAT_NEED_DS DS records to validate a key not found, name in keyname
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000813*/
814int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
815{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000816 unsigned char *psave, *p = (unsigned char *)(header+1);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000817 struct crec *crecp, *recp1;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000818 int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000819 struct blockdata *key;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000820 struct all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000821
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000822 if (ntohs(header->qdcount) != 1 ||
823 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000824 return STAT_INSECURE;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000825
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000826 GETSHORT(qtype, p);
827 GETSHORT(qclass, p);
828
Simon Kelley0fc2f312014-01-08 10:26:58 +0000829 if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000830 return STAT_INSECURE;
831
Simon Kelley0fc2f312014-01-08 10:26:58 +0000832 /* See if we have cached a DS record which validates this key */
833 if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
834 {
835 strcpy(keyname, name);
836 return STAT_NEED_DS;
837 }
838
Simon Kelley0fc2f312014-01-08 10:26:58 +0000839 /* NOTE, we need to find ONE DNSKEY which matches the DS */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000840 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000841 {
842 /* Ensure we have type, class TTL and length */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000843 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000844 return STAT_INSECURE; /* bad packet */
845
846 GETSHORT(qtype, p);
847 GETSHORT(qclass, p);
848 GETLONG(ttl, p);
849 GETSHORT(rdlen, p);
Simon Kelley6f468102014-01-26 23:39:17 +0000850
Simon Kelley0fc2f312014-01-08 10:26:58 +0000851 if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
852 return STAT_INSECURE; /* bad packet */
853
Simon Kelley6f468102014-01-26 23:39:17 +0000854 if (qclass != class || qtype != T_DNSKEY || rc == 2)
855 {
856 p += rdlen;
857 continue;
858 }
859
Simon Kelley0fc2f312014-01-08 10:26:58 +0000860 psave = p;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000861
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000862 GETSHORT(flags, p);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000863 if (*p++ != 3)
864 return STAT_INSECURE;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000865 algo = *p++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000866 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000867 key = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000868
Simon Kelleye7829ae2014-01-22 22:21:51 +0000869 /* key must have zone key flag set */
870 if (flags & 0x100)
871 key = blockdata_alloc((char*)p, rdlen - 4);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000872
873 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000874
Simon Kelley0fc2f312014-01-08 10:26:58 +0000875 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000876 {
877 if (key)
878 blockdata_free(key);
879 return STAT_INSECURE; /* bad packet */
880 }
881
Simon Kelleye7829ae2014-01-22 22:21:51 +0000882 /* No zone key flag or malloc failure */
883 if (!key)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000884 continue;
885
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000886 for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000887 {
888 void *ctx;
889 unsigned char *digest, *ds_digest;
890 const struct nettle_hash *hash;
891
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000892 if (recp1->addr.ds.algo == algo &&
893 recp1->addr.ds.keytag == keytag &&
Simon Kelley824202e2014-01-23 20:59:46 +0000894 recp1->uid == class &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000895 (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
Simon Kelley86bec2d2014-01-13 21:31:20 +0000896 hash_init(hash, &ctx, &digest))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000897
Simon Kelley86bec2d2014-01-13 21:31:20 +0000898 {
899 int wire_len = to_wire(name);
900
901 /* Note that digest may be different between DSs, so
902 we can't move this outside the loop. */
903 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
904 hash->update(ctx, (unsigned int)rdlen, psave);
905 hash->digest(ctx, hash->digest_size, digest);
906
907 from_wire(name);
908
Simon Kelley824202e2014-01-23 20:59:46 +0000909 if (recp1->addr.ds.keylen == (int)hash->digest_size &&
910 (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
911 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
Simon Kelleyf6a2b792014-02-01 14:54:26 +0000912 validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag) == STAT_SECURE)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000913 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000914 valid = 1;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000915 break;
916 }
917 }
918 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000919 blockdata_free(key);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000920 }
921
922 if (valid)
923 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000924 /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000925 cache_start_insert();
926
927 p = skip_questions(header, plen);
928
929 for (j = ntohs(header->ancount); j != 0; j--)
930 {
931 /* Ensure we have type, class TTL and length */
932 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
933 return STAT_INSECURE; /* bad packet */
934
935 GETSHORT(qtype, p);
936 GETSHORT(qclass, p);
937 GETLONG(ttl, p);
938 GETSHORT(rdlen, p);
Simon Kelley8d718cb2014-02-03 16:27:37 +0000939
940 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleye7829ae2014-01-22 22:21:51 +0000941 return STAT_INSECURE; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000942
Simon Kelley8d718cb2014-02-03 16:27:37 +0000943 if (qclass == class && rc == 1)
Simon Kelleye7829ae2014-01-22 22:21:51 +0000944 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000945 psave = p;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000946
Simon Kelley8d718cb2014-02-03 16:27:37 +0000947 if (qtype == T_DNSKEY)
948 {
949 if (rdlen < 4)
950 return STAT_INSECURE; /* bad packet */
951
952 GETSHORT(flags, p);
953 if (*p++ != 3)
954 return STAT_INSECURE;
955 algo = *p++;
956 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
957
958 /* Cache needs to known class for DNSSEC stuff */
959 a.addr.dnssec.class = class;
960
961 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
962 {
963 if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
964 blockdata_free(key);
965 else
966 {
967 a.addr.keytag = keytag;
968 log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
969
970 recp1->addr.key.keylen = rdlen - 4;
971 recp1->addr.key.keydata = key;
972 recp1->addr.key.algo = algo;
973 recp1->addr.key.keytag = keytag;
974 recp1->addr.key.flags = flags;
975 recp1->uid = class;
976 }
977 }
978 }
979 else if (qtype == T_RRSIG)
980 {
981 /* RRSIG, cache if covers DNSKEY RRset */
982 if (rdlen < 18)
983 return STAT_INSECURE; /* bad packet */
984
985 GETSHORT(type_covered, p);
986
987 if (type_covered == T_DNSKEY)
988 {
989 a.addr.dnssec.class = class;
990 a.addr.dnssec.type = type_covered;
991
992 algo = *p++;
993 p += 13; /* labels, orig_ttl, expiration, inception */
994 GETSHORT(keytag, p);
995 if ((key = blockdata_alloc((char*)psave, rdlen)))
996 {
997 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
998 blockdata_free(key);
999 else
1000 {
1001 crecp->uid = class;
1002 crecp->addr.sig.keydata = key;
1003 crecp->addr.sig.keylen = rdlen;
1004 crecp->addr.sig.keytag = keytag;
1005 crecp->addr.sig.type_covered = type_covered;
1006 crecp->addr.sig.algo = algo;
1007 }
1008 }
1009 }
1010 }
Simon Kelleye7829ae2014-01-22 22:21:51 +00001011
Simon Kelley8d718cb2014-02-03 16:27:37 +00001012 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001013 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001014
Simon Kelleye7829ae2014-01-22 22:21:51 +00001015 if (!ADD_RDLEN(header, p, plen, rdlen))
1016 return STAT_INSECURE; /* bad packet */
1017 }
1018
Simon Kelley0fc2f312014-01-08 10:26:58 +00001019 /* commit cache insert. */
1020 cache_end_insert();
1021 return STAT_SECURE;
1022 }
1023
1024 log_query(F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
1025 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001026}
Simon Kelley0fc2f312014-01-08 10:26:58 +00001027
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001028/* The DNS packet is expected to contain the answer to a DS query
1029 Put all DSs in the answer which are valid into the cache.
1030 return codes:
Simon Kelley0fc2f312014-01-08 10:26:58 +00001031 STAT_INSECURE bad packet, no DS in reply.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001032 STAT_SECURE At least one valid DS found and in cache.
1033 STAT_BOGUS At least one DS found, which fails validation.
1034 STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
1035*/
1036
1037int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
1038{
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001039 unsigned char *p = (unsigned char *)(header+1);
1040 int qtype, qclass, val;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001041
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001042 if (ntohs(header->qdcount) != 1 ||
1043 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley8d718cb2014-02-03 16:27:37 +00001044 return STAT_INSECURE;
1045
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001046 GETSHORT(qtype, p);
1047 GETSHORT(qclass, p);
1048
Simon Kelley0fc2f312014-01-08 10:26:58 +00001049 if (qtype != T_DS || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001050 return STAT_INSECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001051
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001052 val = dnssec_validate_reply(now, header, plen, name, keyname, NULL);
1053
Simon Kelley0fc2f312014-01-08 10:26:58 +00001054 if (val == STAT_BOGUS)
Simon Kelley8d718cb2014-02-03 16:27:37 +00001055 {
1056 p = (unsigned char *)(header+1);
1057 extract_name(header, plen, &p, name, 1, 4);
1058 log_query(F_UPSTREAM, name, NULL, "BOGUS DS");
1059 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001060
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001061 return val;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001062}
1063
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001064/* 4034 6.1 */
1065static int hostname_cmp(const char *a, const char *b)
1066{
Simon Kelleydbf72122014-01-21 14:28:02 +00001067 char *sa, *ea, *ca, *sb, *eb, *cb;
1068 unsigned char ac, bc;
1069
1070 sa = ea = (char *)a + strlen(a);
1071 sb = eb = (char *)b + strlen(b);
1072
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001073 while (1)
1074 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001075 while (sa != a && *(sa-1) != '.')
1076 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001077
Simon Kelleydbf72122014-01-21 14:28:02 +00001078 while (sb != b && *(sb-1) != '.')
1079 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001080
Simon Kelleydbf72122014-01-21 14:28:02 +00001081 ca = sa;
1082 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001083
Simon Kelleydbf72122014-01-21 14:28:02 +00001084 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001085 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001086 if (ca == ea)
1087 {
1088 if (cb == eb)
1089 break;
1090
1091 return -1;
1092 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001093
Simon Kelleydbf72122014-01-21 14:28:02 +00001094 if (cb == eb)
1095 return 1;
1096
1097 ac = (unsigned char) *ca++;
1098 bc = (unsigned char) *cb++;
1099
1100 if (ac >= 'A' && ac <= 'Z')
1101 ac += 'a' - 'A';
1102 if (bc >= 'A' && bc <= 'Z')
1103 bc += 'a' - 'A';
1104
Simon Kelley979cdf92014-01-21 16:26:41 +00001105 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001106 return -1;
1107 else if (ac != bc)
1108 return 1;
1109 }
1110
1111
1112 if (sa == a)
1113 {
1114 if (sb == b)
1115 return 0;
1116
1117 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001118 }
1119
Simon Kelleydbf72122014-01-21 14:28:02 +00001120 if (sb == b)
1121 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001122
Simon Kelleydbf72122014-01-21 14:28:02 +00001123 ea = sa--;
1124 eb = sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001125 }
1126}
1127
1128
Simon Kelley0fc2f312014-01-08 10:26:58 +00001129/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001130/* Returns are the same as validate_rrset, plus the class if the missing key is in *class */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001131int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001132{
Simon Kelley0fc2f312014-01-08 10:26:58 +00001133 unsigned char *ans_start, *p1, *p2;
1134 int type1, class1, rdlen1, type2, class2, rdlen2;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001135 int i, j, rc, have_nsec, have_nsec_equal, cname_count = 5;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001136
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001137 if (RCODE(header) == SERVFAIL)
1138 return STAT_BOGUS;
1139
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001140 if ((RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR) || ntohs(header->qdcount) != 1)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001141 return STAT_INSECURE;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001142
Simon Kelley0fc2f312014-01-08 10:26:58 +00001143 if (!(ans_start = skip_questions(header, plen)))
1144 return STAT_INSECURE;
1145
1146 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001147 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001148 if (!extract_name(header, plen, &p1, name, 1, 10))
1149 return STAT_INSECURE; /* bad packet */
1150
1151 GETSHORT(type1, p1);
1152 GETSHORT(class1, p1);
1153 p1 += 4; /* TTL */
1154 GETSHORT(rdlen1, p1);
1155
1156 /* Don't try and validate RRSIGs! */
1157 if (type1 != T_RRSIG)
1158 {
1159 /* Check if we've done this RRset already */
1160 for (p2 = ans_start, j = 0; j < i; j++)
1161 {
1162 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1163 return STAT_INSECURE; /* bad packet */
1164
1165 GETSHORT(type2, p2);
1166 GETSHORT(class2, p2);
1167 p2 += 4; /* TTL */
1168 GETSHORT(rdlen2, p2);
1169
1170 if (type2 == type1 && class2 == class1 && rc == 1)
1171 break; /* Done it before: name, type, class all match. */
1172
1173 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1174 return STAT_INSECURE;
1175 }
1176
1177 /* Not done, validate now */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001178 if (j == i)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001179 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001180 int ttl, keytag, algo, digest, type_covered;
1181 unsigned char *psave;
1182 struct all_addr a;
1183 struct blockdata *key;
1184 struct crec *crecp;
1185
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001186 if ((rc = validate_rrset(now, header, plen, class1, type1, name, keyname, NULL, 0, 0, 0)) != STAT_SECURE)
1187 {
1188 if (class)
1189 *class = class1; /* Class for DS or DNSKEY */
1190 return rc;
1191 }
1192
Simon Kelley8d718cb2014-02-03 16:27:37 +00001193 /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
1194 cache_start_insert();
1195
1196 for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001197 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001198 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1199 return STAT_INSECURE; /* bad packet */
1200
1201 GETSHORT(type2, p2);
1202 GETSHORT(class2, p2);
1203 GETLONG(ttl, p2);
1204 GETSHORT(rdlen2, p2);
1205
1206 if (!CHECK_LEN(header, p2, plen, rdlen2))
1207 return STAT_INSECURE; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001208
Simon Kelley8d718cb2014-02-03 16:27:37 +00001209 if (class2 == class1 && rc == 1)
1210 {
1211 psave = p2;
1212
1213 if (type1 == T_DS && type2 == T_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001214 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001215 if (rdlen2 < 4)
1216 return STAT_INSECURE; /* bad packet */
1217
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001218 GETSHORT(keytag, p2);
1219 algo = *p2++;
1220 digest = *p2++;
1221
1222 /* Cache needs to known class for DNSSEC stuff */
1223 a.addr.dnssec.class = class2;
1224
Simon Kelley8d718cb2014-02-03 16:27:37 +00001225 if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001226 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001227 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
1228 blockdata_free(key);
1229 else
1230 {
1231 a.addr.keytag = keytag;
1232 log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
1233 crecp->addr.ds.digest = digest;
1234 crecp->addr.ds.keydata = key;
1235 crecp->addr.ds.algo = algo;
1236 crecp->addr.ds.keytag = keytag;
1237 crecp->uid = class2;
1238 crecp->addr.ds.keylen = rdlen2 - 4;
1239 }
1240 }
1241 }
1242 else if (type2 == T_RRSIG)
1243 {
1244 if (rdlen2 < 18)
1245 return STAT_INSECURE; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001246
Simon Kelley8d718cb2014-02-03 16:27:37 +00001247 GETSHORT(type_covered, p2);
1248
1249 if (type_covered == type1 &&
1250 (type_covered == T_A || type_covered == T_AAAA ||
1251 type_covered == T_CNAME || type_covered == T_DS ||
1252 type_covered == T_DNSKEY || type_covered == T_PTR))
1253 {
1254 a.addr.dnssec.type = type_covered;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001255 a.addr.dnssec.class = class1;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001256
1257 algo = *p2++;
1258 p2 += 13; /* labels, orig_ttl, expiration, inception */
1259 GETSHORT(keytag, p2);
1260
1261 if ((key = blockdata_alloc((char*)psave, rdlen2)))
1262 {
1263 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
1264 blockdata_free(key);
1265 else
1266 {
1267 crecp->uid = class1;
1268 crecp->addr.sig.keydata = key;
1269 crecp->addr.sig.keylen = rdlen2;
1270 crecp->addr.sig.keytag = keytag;
1271 crecp->addr.sig.type_covered = type_covered;
1272 crecp->addr.sig.algo = algo;
1273 }
1274 }
1275 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001276 }
1277
Simon Kelley8d718cb2014-02-03 16:27:37 +00001278 p2 = psave;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001279 }
1280
Simon Kelley8d718cb2014-02-03 16:27:37 +00001281 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1282 return STAT_INSECURE; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001283 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001284
1285 cache_end_insert();
Simon Kelley0fc2f312014-01-08 10:26:58 +00001286 }
1287 }
1288
1289 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1290 return STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001291 }
1292
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001293 /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
1294
1295 p1 = (unsigned char *)(header+1);
1296
1297 if (!extract_name(header, plen, &p1, name, 1, 4))
1298 return STAT_INSECURE;
1299
1300 GETSHORT(type1, p1);
1301 GETSHORT(class1, p1);
1302
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001303 /* Can't validate RRSIG query */
1304 if (type1 == T_RRSIG)
1305 return STAT_INSECURE;
1306
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001307 cname_loop:
1308 for (j = ntohs(header->ancount); j != 0; j--)
1309 {
1310 if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
1311 return STAT_INSECURE; /* bad packet */
1312
1313 GETSHORT(type2, p1);
1314 GETSHORT(class2, p1);
1315 p1 += 4; /* TTL */
1316 GETSHORT(rdlen2, p1);
1317
1318 if (rc == 1 && class1 == class2)
1319 {
1320 /* Do we have an answer for the question? */
1321 if (type1 == type2)
1322 return RCODE(header) == NXDOMAIN ? STAT_INSECURE : STAT_SECURE;
1323 else if (type2 == T_CNAME)
1324 {
1325 /* looped CNAMES */
1326 if (!cname_count-- ||
1327 !extract_name(header, plen, &p1, name, 1, 0) ||
1328 !(p1 = skip_questions(header, plen)))
1329 return STAT_INSECURE;
1330
1331 goto cname_loop;
1332 }
1333 }
1334
1335 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1336 return STAT_INSECURE;
1337 }
1338
1339 /* NXDOMAIN or NODATA reply, look for NSEC records to support that.
1340 At this point, p1 points to the start of the auth section.
1341 Use keyname as workspace */
1342 for (have_nsec = 0, have_nsec_equal = 0, p2 = NULL, rdlen2 = 0, j = ntohs(header->nscount); j != 0; j--)
1343 {
1344 unsigned char *nsec_start = p1;
1345 if (!extract_name(header, plen, &p1, keyname, 1, 10))
1346 return STAT_INSECURE; /* bad packet */
1347
1348 GETSHORT(type2, p1);
1349 GETSHORT(class2, p1);
1350 p1 += 4; /* TTL */
1351 GETSHORT(rdlen1, p1);
1352
1353 if (class1 == class2 && type2 == T_NSEC)
1354 {
1355 have_nsec = 1;
1356 rc = hostname_cmp(name, keyname);
1357
1358 if (rc >= 0)
1359 {
1360 if (p2)
1361 {
1362 unsigned char *psave = p2;
1363 /* new NSEC is smaller than name,
1364 is it bigger than previous one? */
1365
1366 /* get previous one into name buffer */
1367 if (!extract_name(header, plen, &psave, name, 1, 0))
1368 return STAT_INSECURE; /* bad packet */
1369
1370 if (hostname_cmp(name, keyname) < 0)
1371 {
1372 p2 = nsec_start;
1373 rdlen2 = rdlen1;
1374 }
1375
1376 /* restore query name */
1377 psave = (unsigned char *)(header+1);
1378 if (!extract_name(header, plen, &psave, name, 1, 0))
1379 return STAT_INSECURE;
1380 }
1381 else
1382 {
1383 /* There was no previous best candidate */
1384 p2 = nsec_start;
1385 rdlen2 = rdlen1;
1386 }
1387 }
1388
1389 if (rc == 0)
1390 have_nsec_equal = 1;
1391 }
1392
1393 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1394 return STAT_INSECURE;
1395 }
1396
1397
1398 if (p2)
1399 {
1400 unsigned char *psave;
1401 p2 = skip_name(p2, header, plen, 0);
1402 p2 += 10; /* type, class, ttl, rdlen */
1403 psave = p2;
1404 extract_name(header, plen, &p2, keyname, 1, 0);
1405 rdlen2 -= p2 - psave;
1406 }
1407
1408 /* At this point, have_nsec is set if there's at least one NSEC
1409 have_nsec_equal is set if there's an NSEC with the same name as the query;
1410 p2 points to the type bit maps of the biggest NSEC smaller than or equal to the query
1411 or NULL if the query is smaller than all of them.
1412 Keyname holds the next domain name for that NSEC.
1413 rdlen2 is the length of the bitmap field */
1414
1415
1416 if (RCODE(header) == NOERROR && have_nsec_equal)
1417 {
1418 int offset = (type1 & 0xff) >> 3;
1419 int mask = 0x80 >> (type1 & 0x07);
1420
1421 while (rdlen2 >= 2)
1422 {
1423 if (p2[0] == type1 >> 8)
1424 {
1425 /* Does the NSEC say our type exists? */
1426 if (offset < p2[1] &&
1427 (p2[offset+2] & mask) != 0)
1428 return STAT_INSECURE;
1429
1430 break; /* finshed checking */
1431 }
1432
1433 rdlen2 -= p2[1];
1434 p2 += p2[1];
1435 }
1436
1437 return STAT_SECURE;
1438 }
1439
1440 if (RCODE(header) == NXDOMAIN && have_nsec)
1441 {
1442 if (!p2 || hostname_cmp(name, keyname) < 0)
1443 return STAT_SECURE; /* Before the first, or in a proven gap */
1444 }
1445
1446 return STAT_INSECURE;
Giovanni Bajoadca3e92012-04-25 17:46:53 +02001447}
1448
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001449
Giovanni Bajo3471f182012-04-25 17:49:16 +02001450/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001451int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02001452{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001453 if (alg == 1)
1454 {
1455 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
1456 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001457 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001458 }
1459 else
1460 {
Simon Kelley1633e302014-02-10 16:42:46 +00001461 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001462 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02001463
Simon Kelley0fc2f312014-01-08 10:26:58 +00001464 for (i = 0; i < keylen; ++i)
1465 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00001466
Simon Kelley0fc2f312014-01-08 10:26:58 +00001467 ac += (ac >> 16) & 0xffff;
1468 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001469 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02001470}
1471
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001472size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr)
1473{
1474 unsigned char *p;
Simon Kelley610e7822014-02-06 14:45:17 +00001475 char *types = querystr("dnssec-query", type);
Giovanni Bajo0304d282012-05-02 03:29:52 +02001476
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001477 if (addr->sa.sa_family == AF_INET)
1478 log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
1479#ifdef HAVE_IPV6
1480 else
1481 log_query(F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
1482#endif
1483
1484 header->qdcount = htons(1);
1485 header->ancount = htons(0);
1486 header->nscount = htons(0);
1487 header->arcount = htons(0);
1488
1489 header->hb3 = HB3_RD;
1490 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00001491 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1492 this allows it to select auth servers when one is returning bad data. */
1493 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001494
1495 /* ID filled in later */
1496
1497 p = (unsigned char *)(header+1);
1498
1499 p = do_rfc1035_name(p, name);
1500 *p++ = 0;
1501 PUTSHORT(type, p);
1502 PUTSHORT(class, p);
1503
1504 return add_do_bit(header, p - (unsigned char *)header, end);
1505}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001506
1507unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
1508{
1509 int q;
1510 unsigned int len;
1511 unsigned char *p = (unsigned char *)(header+1);
1512 const struct nettle_hash *hash;
1513 void *ctx;
1514 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001515
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001516 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
1517 return NULL;
1518
1519 for (q = ntohs(header->qdcount); q != 0; q--)
1520 {
1521 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00001522 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001523
1524 len = to_wire(name);
1525 hash->update(ctx, len, (unsigned char *)name);
1526 /* CRC the class and type as well */
1527 hash->update(ctx, 4, p);
1528
1529 p += 4;
1530 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00001531 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001532 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00001533
1534 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001535 return digest;
1536}
1537
Simon Kelley0fc2f312014-01-08 10:26:58 +00001538#endif /* HAVE_DNSSEC */