blob: 13e67872569a5143699695eebaac3be83ac6168a [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 Kelleyebe95a82014-02-13 14:56:10 +000024#include <nettle/ecdsa.h>
25#include <nettle/ecc-curve.h>
Simon Kelley86bec2d2014-01-13 21:31:20 +000026#include <nettle/nettle-meta.h>
27#include <gmp.h>
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000028
Giovanni Bajoe292e932012-04-22 14:32:02 +020029#define SERIAL_UNDEF -100
30#define SERIAL_EQ 0
31#define SERIAL_LT -1
32#define SERIAL_GT 1
33
Simon Kelley86bec2d2014-01-13 21:31:20 +000034/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
35static char *ds_digest_name(int digest)
36{
37 switch (digest)
38 {
39 case 1: return "sha1";
40 case 2: return "sha256";
41 case 3: return "gosthash94";
42 case 4: return "sha384";
43 default: return NULL;
44 }
45}
46
47/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
48static char *algo_digest_name(int algo)
49{
50 switch (algo)
51 {
52 case 1: return "md5";
53 case 3: return "sha1";
54 case 5: return "sha1";
55 case 6: return "sha1";
56 case 7: return "sha1";
57 case 8: return "sha256";
58 case 10: return "sha512";
59 case 12: return "gosthash94";
60 case 13: return "sha256";
61 case 14: return "sha384";
62 default: return NULL;
63 }
64}
65
66/* Find pointer to correct hash function in nettle library */
67static const struct nettle_hash *hash_find(char *name)
68{
69 int i;
70
71 if (!name)
72 return NULL;
73
74 for (i = 0; nettle_hashes[i]; i++)
75 {
76 if (strcmp(nettle_hashes[i]->name, name) == 0)
77 return nettle_hashes[i];
78 }
79
80 return NULL;
81}
82
83/* expand ctx and digest memory allocations if necessary and init hash function */
84static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
85{
86 static void *ctx = NULL;
87 static unsigned char *digest = NULL;
88 static unsigned int ctx_sz = 0;
89 static unsigned int digest_sz = 0;
90
91 void *new;
92
93 if (ctx_sz < hash->context_size)
94 {
95 if (!(new = whine_malloc(hash->context_size)))
96 return 0;
97 if (ctx)
98 free(ctx);
99 ctx = new;
100 ctx_sz = hash->context_size;
101 }
102
103 if (digest_sz < hash->digest_size)
104 {
105 if (!(new = whine_malloc(hash->digest_size)))
106 return 0;
107 if (digest)
108 free(digest);
109 digest = new;
110 digest_sz = hash->digest_size;
111 }
112
113 *ctxp = ctx;
114 *digestp = digest;
115
116 hash->init(ctx);
117
118 return 1;
119}
120
121static int rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
122 unsigned char *digest, int algo)
123{
124 unsigned char *p;
125 size_t exp_len;
126
127 static struct rsa_public_key *key = NULL;
128 static mpz_t sig_mpz;
129
130 if (key == NULL)
131 {
132 if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
133 return 0;
134
135 nettle_rsa_public_key_init(key);
136 mpz_init(sig_mpz);
137 }
138
139 if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
140 return 0;
141
142 key_len--;
143 if ((exp_len = *p++) == 0)
144 {
145 GETSHORT(exp_len, p);
146 key_len -= 2;
147 }
148
149 if (exp_len >= key_len)
150 return 0;
151
152 key->size = key_len - exp_len;
153 mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
154 mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
155
156 mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
157
158 switch (algo)
159 {
160 case 1:
161 return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
162 case 5: case 7:
163 return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
164 case 8:
165 return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
166 case 10:
167 return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
168 }
169
170 return 0;
171}
172
173static int dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
174 unsigned char *digest, int algo)
175{
176 unsigned char *p;
177 unsigned int t;
178
179 static struct dsa_public_key *key = NULL;
180 static struct dsa_signature *sig_struct;
181
182 if (key == NULL)
183 {
184 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
185 !(key = whine_malloc(sizeof(struct dsa_public_key))))
186 return 0;
187
188 nettle_dsa_public_key_init(key);
189 nettle_dsa_signature_init(sig_struct);
190 }
191
192 if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
193 return 0;
194
195 t = *p++;
196
197 if (key_len < (213 + (t * 24)))
198 return 0;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000199
Simon Kelley86bec2d2014-01-13 21:31:20 +0000200 mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
201 mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
202 mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
203 mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
204
205 mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
206 mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
207
208 (void)algo;
Simon Kelleyebe95a82014-02-13 14:56:10 +0000209
Simon Kelley86bec2d2014-01-13 21:31:20 +0000210 return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
211}
212
Simon Kelleyebe95a82014-02-13 14:56:10 +0000213static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
214 unsigned char *digest, size_t digest_len, int algo)
215{
216 unsigned char *p;
217 unsigned int t;
218 struct ecc_point *key;
219
220 static struct ecc_point *key_256 = NULL, *key_384 = NULL;
221 static mpz_t x, y;
222 static struct dsa_signature *sig_struct;
223
224 if (!sig_struct)
225 {
226 if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
227 return 0;
228
229 nettle_dsa_signature_init(sig_struct);
230 mpz_init(x);
231 mpz_init(y);
232 }
233
234 switch (algo)
235 {
236 case 13:
237 if (!key_256)
238 {
239 if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
240 return 0;
241
242 nettle_ecc_point_init(key_256, &nettle_secp_256r1);
243 }
244
245 key = key_256;
246 t = 32;
247 break;
248
249 case 14:
250 if (!key_384)
251 {
252 if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
253 return 0;
254
255 nettle_ecc_point_init(key_384, &nettle_secp_384r1);
256 }
257
258 key = key_384;
259 t = 48;
260 break;
261
262 default:
263 return 0;
264 }
265
266 if (sig_len != 2*t || key_len != 2*t ||
267 (p = blockdata_retrieve(key_data, key_len, NULL)))
268 return 0;
269
270 mpz_import(x, t , 1, 1, 0, 0, p);
271 mpz_import(y, t , 1, 1, 0, 0, p + t);
272
273 if (!ecc_point_set(key, x, y))
274 return 0;
275
276 mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
277 mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
278
279 return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
280}
281
Simon Kelley86bec2d2014-01-13 21:31:20 +0000282static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
Simon Kelleyebe95a82014-02-13 14:56:10 +0000283 unsigned char *digest, size_t digest_len, int algo)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000284{
285 switch (algo)
286 {
287 case 1: case 5: case 7: case 8: case 10:
288 return rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
289
290 case 3: case 6:
291 return dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
Simon Kelleyebe95a82014-02-13 14:56:10 +0000292
293 case 13: case 14:
294 return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
295}
Simon Kelley86bec2d2014-01-13 21:31:20 +0000296
297 return 0;
298}
299
Simon Kelley0fc2f312014-01-08 10:26:58 +0000300/* Convert from presentation format to wire format, in place.
301 Also map UC -> LC.
302 Note that using extract_name to get presentation format
303 then calling to_wire() removes compression and maps case,
304 thus generating names in canonical form.
305 Calling to_wire followed by from_wire is almost an identity,
306 except that the UC remains mapped to LC.
307*/
308static int to_wire(char *name)
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200309{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000310 unsigned char *l, *p, term;
311 int len;
312
313 for (l = (unsigned char*)name; *l != 0; l = p)
314 {
315 for (p = l; *p != '.' && *p != 0; p++)
316 if (*p >= 'A' && *p <= 'Z')
317 *p = *p - 'A' + 'a';
318
319 term = *p;
320
321 if ((len = p - l) != 0)
322 memmove(l+1, l, len);
323 *l = len;
324
325 p++;
326
327 if (term == 0)
328 *p = 0;
329 }
330
331 return l + 1 - (unsigned char *)name;
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200332}
333
Simon Kelley0fc2f312014-01-08 10:26:58 +0000334/* Note: no compression allowed in input. */
335static void from_wire(char *name)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200336{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000337 unsigned char *l;
338 int len;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200339
Simon Kelley0fc2f312014-01-08 10:26:58 +0000340 for (l = (unsigned char *)name; *l != 0; l += len+1)
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200341 {
Simon Kelley0fc2f312014-01-08 10:26:58 +0000342 len = *l;
343 memmove(l, l+1, len);
344 l[len] = '.';
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200345 }
Giovanni Bajo7f0485c2012-04-28 12:59:49 +0200346
Simon Kelley0fc2f312014-01-08 10:26:58 +0000347 *(l-1) = 0;
Giovanni Bajo13e435e2012-04-27 03:19:40 +0200348}
349
Simon Kelley5ada8882014-01-09 22:25:03 +0000350/* Input in presentation format */
351static int count_labels(char *name)
352{
353 int i;
354
355 if (*name == 0)
356 return 0;
357
358 for (i = 0; *name; name++)
359 if (*name == '.')
360 i++;
361
362 return i+1;
363}
364
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000365/* Implement RFC1982 wrapped compare for 32-bit numbers */
366static int serial_compare_32(unsigned long s1, unsigned long s2)
Giovanni Bajo0852d762012-04-28 03:49:24 +0200367{
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000368 if (s1 == s2)
369 return SERIAL_EQ;
Giovanni Bajo0852d762012-04-28 03:49:24 +0200370
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000371 if ((s1 < s2 && (s2 - s1) < (1UL<<31)) ||
372 (s1 > s2 && (s1 - s2) > (1UL<<31)))
373 return SERIAL_LT;
374 if ((s1 < s2 && (s2 - s1) > (1UL<<31)) ||
375 (s1 > s2 && (s1 - s2) < (1UL<<31)))
376 return SERIAL_GT;
377 return SERIAL_UNDEF;
378}
Giovanni Bajo0852d762012-04-28 03:49:24 +0200379
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000380/* Check whether today/now is between date_start and date_end */
381static int check_date_range(unsigned long date_start, unsigned long date_end)
382{
383 unsigned long curtime = time(0);
384
385 /* We must explicitly check against wanted values, because of SERIAL_UNDEF */
386 return serial_compare_32(curtime, date_start) == SERIAL_GT
387 && serial_compare_32(curtime, date_end) == SERIAL_LT;
388}
389
390static u16 *get_desc(int type)
391{
392 /* List of RRtypes which include domains in the data.
393 0 -> domain
394 integer -> no of plain bytes
395 -1 -> end
396
397 zero is not a valid RRtype, so the final entry is returned for
398 anything which needs no mangling.
399 */
400
401 static u16 rr_desc[] =
402 {
403 T_NS, 0, -1,
404 T_MD, 0, -1,
405 T_MF, 0, -1,
406 T_CNAME, 0, -1,
407 T_SOA, 0, 0, -1,
408 T_MB, 0, -1,
409 T_MG, 0, -1,
410 T_MR, 0, -1,
411 T_PTR, 0, -1,
412 T_MINFO, 0, 0, -1,
413 T_MX, 2, 0, -1,
414 T_RP, 0, 0, -1,
415 T_AFSDB, 2, 0, -1,
416 T_RT, 2, 0, -1,
417 T_SIG, 18, 0, -1,
418 T_PX, 2, 0, 0, -1,
419 T_NXT, 0, -1,
420 T_KX, 2, 0, -1,
421 T_SRV, 6, 0, -1,
422 T_DNAME, 0, -1,
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000423 0, -1 /* wildcard/catchall */
424 };
425
426 u16 *p = rr_desc;
427
428 while (*p != type && *p != 0)
429 while (*p++ != (u16)-1);
430
431 return p+1;
432}
433
434/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
435 data, pointed to by *p, should be used raw. */
436static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff,
437 unsigned char **p, u16 **desc)
438{
439 int d = **desc;
440
441 (*desc)++;
442
443 /* No more data needs mangling */
444 if (d == (u16)-1)
Giovanni Bajof119ed32012-05-02 00:31:55 +0200445 return 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000446
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000447 if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
448 /* domain-name, canonicalise */
449 return to_wire(buff);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000450 else
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000451 {
452 /* plain data preceding a domain-name, don't run off the end of the data */
453 if ((end - *p) < d)
454 d = end - *p;
455
456 if (d != 0)
457 {
458 memcpy(buff, *p, d);
459 *p += d;
460 }
461
462 return d;
463 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000464}
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000465
466/* Bubble sort the RRset into the canonical order.
467 Note that the byte-streams from two RRs may get unsynced: consider
468 RRs which have two domain-names at the start and then other data.
469 The domain-names may have different lengths in each RR, but sort equal
470
471 ------------
472 |abcde|fghi|
473 ------------
474 |abcd|efghi|
475 ------------
476
477 leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
478*/
479
480static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
481 unsigned char **rrset, char *buff1, char *buff2)
482{
483 int swap, quit, i;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000484
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000485 do
486 {
487 for (swap = 0, i = 0; i < rrsetidx-1; i++)
488 {
489 int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
490 u16 *dp1, *dp2;
491 unsigned char *end1, *end2;
492 unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
493 unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
494
495 p1 += 8; /* skip class, type, ttl */
496 GETSHORT(rdlen1, p1);
497 end1 = p1 + rdlen1;
498
499 p2 += 8; /* skip class, type, ttl */
500 GETSHORT(rdlen2, p2);
501 end2 = p2 + rdlen2;
502
503 dp1 = dp2 = rr_desc;
504
Simon Kelley1486a9c2014-01-10 11:39:14 +0000505 for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000506 {
Simon Kelley1486a9c2014-01-10 11:39:14 +0000507 if (left1 != 0)
508 memmove(buff1, buff1 + len1 - left1, left1);
509
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000510 if ((len1 = get_rdata(header, plen, end1, buff1 + left1, &p1, &dp1)) == 0)
511 {
512 quit = 1;
513 len1 = end1 - p1;
514 memcpy(buff1 + left1, p1, len1);
515 }
516 len1 += left1;
517
Simon Kelley1486a9c2014-01-10 11:39:14 +0000518 if (left2 != 0)
519 memmove(buff2, buff2 + len2 - left2, left2);
520
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000521 if ((len2 = get_rdata(header, plen, end2, buff2 + left2, &p2, &dp2)) == 0)
522 {
523 quit = 1;
524 len2 = end2 - p2;
525 memcpy(buff2 + left2, p2, len2);
526 }
527 len2 += left2;
528
529 if (len1 > len2)
Simon Kelley1486a9c2014-01-10 11:39:14 +0000530 left1 = len1 - len2, left2 = 0, len = len2;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000531 else
Simon Kelley1486a9c2014-01-10 11:39:14 +0000532 left2 = len2 - len1, left1 = 0, len = len1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000533
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000534 rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000535
Simon Kelley4619d942014-01-16 19:53:06 +0000536 if (rc > 0 || (rc == 0 && quit && len1 > len2))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000537 {
538 unsigned char *tmp = rrset[i+1];
539 rrset[i+1] = rrset[i];
540 rrset[i] = tmp;
541 swap = quit = 1;
542 }
Simon Kelley6fd6dac2014-01-21 20:17:40 +0000543 else if (rc < 0)
544 quit = 1;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000545 }
546 }
547 } while (swap);
548}
549
550/* Validate a single RRset (class, type, name) in the supplied DNS reply
551 Return code:
552 STAT_SECURE if it validates.
553 STAT_INSECURE can't validate (no RRSIG, bad packet).
554 STAT_BOGUS signature is wrong.
555 STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
556
557 if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
558 otherwise find the key in the cache.
559*/
560static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class,
Simon Kelleye7829ae2014-01-22 22:21:51 +0000561 int type, char *name, char *keyname, struct blockdata *key, int keylen, int algo_in, int keytag_in)
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000562{
563 static unsigned char **rrset = NULL, **sigs = NULL;
564 static int rrset_sz = 0, sig_sz = 0;
565
566 unsigned char *p;
Simon Kelley5ada8882014-01-09 22:25:03 +0000567 int rrsetidx, sigidx, res, rdlen, j, name_labels;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000568 struct crec *crecp = NULL;
569 int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
570 u16 *rr_desc = get_desc(type);
571
572 if (!(p = skip_questions(header, plen)))
573 return STAT_INSECURE;
574
Simon Kelley5ada8882014-01-09 22:25:03 +0000575 name_labels = count_labels(name); /* For 4035 5.3.2 check */
576
577 /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000578 for (rrsetidx = 0, sigidx = 0, j = ntohs(header->ancount) + ntohs(header->nscount);
579 j != 0; j--)
580 {
581 unsigned char *pstart, *pdata;
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000582 int stype, sclass;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000583
584 pstart = p;
585
586 if (!(res = extract_name(header, plen, &p, name, 0, 10)))
587 return STAT_INSECURE; /* bad packet */
588
589 GETSHORT(stype, p);
590 GETSHORT(sclass, p);
Simon Kelleyb98d22c2014-02-04 16:57:25 +0000591 p += 4; /* TTL */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000592
593 pdata = p;
594
595 GETSHORT(rdlen, p);
596
Simon Kelleye7829ae2014-01-22 22:21:51 +0000597 if (!CHECK_LEN(header, p, plen, rdlen))
598 return STAT_INSECURE;
599
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000600 if (res == 1 && sclass == class)
601 {
602 if (stype == type)
603 {
604 if (rrsetidx == rrset_sz)
605 {
606 unsigned char **new;
607
Simon Kelleybb201c22014-02-06 12:01:05 +0000608 /* Protect against insane/maliciuos queries which bloat the workspace
609 and eat CPU in the sort */
610 if (rrsetidx >= 100)
611 return STAT_INSECURE;
612
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000613 /* expand */
614 if (!(new = whine_malloc((rrset_sz + 5) * sizeof(unsigned char **))))
615 return STAT_INSECURE;
616
617 if (rrset)
618 {
619 memcpy(new, rrset, rrset_sz * sizeof(unsigned char **));
620 free(rrset);
621 }
622
623 rrset = new;
624 rrset_sz += 5;
625 }
626 rrset[rrsetidx++] = pstart;
627 }
628
629 if (stype == T_RRSIG)
630 {
Simon Kelley5ada8882014-01-09 22:25:03 +0000631 if (rdlen < 18)
632 return STAT_INSECURE; /* bad packet */
633
634 GETSHORT(type_covered, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000635
Simon Kelleye7829ae2014-01-22 22:21:51 +0000636 if (type_covered == type)
Simon Kelley5ada8882014-01-09 22:25:03 +0000637 {
638 if (sigidx == sig_sz)
639 {
640 unsigned char **new;
641
642 /* expand */
643 if (!(new = whine_malloc((sig_sz + 5) * sizeof(unsigned char **))))
644 return STAT_INSECURE;
645
646 if (sigs)
647 {
648 memcpy(new, sigs, sig_sz * sizeof(unsigned char **));
649 free(sigs);
650 }
651
652 sigs = new;
653 sig_sz += 5;
654 }
655
656 sigs[sigidx++] = pdata;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000657 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000658 p = pdata + 2; /* restore for ADD_RDLEN */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000659 }
660 }
661
662 if (!ADD_RDLEN(header, p, plen, rdlen))
663 return STAT_INSECURE;
664 }
665
666 /* RRset empty, no RRSIGs */
667 if (rrsetidx == 0 || sigidx == 0)
668 return STAT_INSECURE;
669
670 /* Sort RRset records into canonical order.
671 Note that at this point keyname and name buffs are
672 unused, and used as workspace by the sort. */
673 sort_rrset(header, plen, rr_desc, rrsetidx, rrset, name, keyname);
674
675 /* Now try all the sigs to try and find one which validates */
676 for (j = 0; j <sigidx; j++)
677 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000678 unsigned char *psav, *sig;
679 int i, wire_len, sig_len;
680 const struct nettle_hash *hash;
681 void *ctx;
682 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000683 u32 nsigttl;
684
685 p = sigs[j];
Simon Kelley5ada8882014-01-09 22:25:03 +0000686 GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000687 psav = p;
688
Simon Kelley5ada8882014-01-09 22:25:03 +0000689 p += 2; /* type_covered - already checked */
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000690 algo = *p++;
691 labels = *p++;
692 GETLONG(orig_ttl, p);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000693 GETLONG(sig_expiration, p);
694 GETLONG(sig_inception, p);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000695 GETSHORT(key_tag, p);
696
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000697 if (!extract_name(header, plen, &p, keyname, 1, 0))
698 return STAT_INSECURE;
699
Simon Kelleye7829ae2014-01-22 22:21:51 +0000700 if (!check_date_range(sig_inception, sig_expiration) ||
701 labels > name_labels ||
702 !(hash = hash_find(algo_digest_name(algo))) ||
703 !hash_init(hash, &ctx, &digest))
704 continue;
705
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000706 /* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
707 if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
708 return STAT_NEED_KEY;
709
Simon Kelley86bec2d2014-01-13 21:31:20 +0000710 sig = p;
711 sig_len = rdlen - (p - psav);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000712
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000713 nsigttl = htonl(orig_ttl);
714
Simon Kelley86bec2d2014-01-13 21:31:20 +0000715 hash->update(ctx, 18, psav);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000716 wire_len = to_wire(keyname);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000717 hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000718 from_wire(keyname);
719
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000720 for (i = 0; i < rrsetidx; ++i)
721 {
722 int seg;
723 unsigned char *end, *cp;
Simon Kelley5ada8882014-01-09 22:25:03 +0000724 char *name_start = name;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000725 u16 len, *dp;
726
727 p = rrset[i];
728 if (!extract_name(header, plen, &p, name, 1, 10))
729 return STAT_INSECURE;
Simon Kelley5ada8882014-01-09 22:25:03 +0000730
731 /* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
732 if (labels < name_labels)
733 {
734 int k;
735 for (k = name_labels - labels; k != 0; k--)
736 while (*name_start != '.' && *name_start != 0)
737 name_start++;
738 name_start--;
739 *name_start = '*';
740 }
741
742 wire_len = to_wire(name_start);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000743 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
744 hash->update(ctx, 4, p); /* class and type */
745 hash->update(ctx, 4, (unsigned char *)&nsigttl);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000746
747 p += 8; /* skip class, type, ttl */
748 GETSHORT(rdlen, p);
Simon Kelley5ada8882014-01-09 22:25:03 +0000749 if (!CHECK_LEN(header, p, plen, rdlen))
750 return STAT_INSECURE;
751
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000752 end = p + rdlen;
753
754 /* canonicalise rdata and calculate length of same, use name buffer as workspace */
755 cp = p;
756 dp = rr_desc;
757 for (len = 0; (seg = get_rdata(header, plen, end, name, &cp, &dp)) != 0; len += seg);
758 len += end - cp;
759 len = htons(len);
Simon Kelley86bec2d2014-01-13 21:31:20 +0000760 hash->update(ctx, 2, (unsigned char *)&len);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000761
762 /* Now canonicalise again and digest. */
763 cp = p;
764 dp = rr_desc;
765 while ((seg = get_rdata(header, plen, end, name, &cp, &dp)))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000766 hash->update(ctx, seg, (unsigned char *)name);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000767 if (cp != end)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000768 hash->update(ctx, end - cp, cp);
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000769 }
Simon Kelley86bec2d2014-01-13 21:31:20 +0000770
771 hash->digest(ctx, hash->digest_size, digest);
772
Simon Kelley5ada8882014-01-09 22:25:03 +0000773 /* namebuff used for workspace above, restore to leave unchanged on exit */
774 p = (unsigned char*)(rrset[0]);
775 extract_name(header, plen, &p, name, 1, 0);
776
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000777 if (key)
778 {
779 if (algo_in == algo && keytag_in == key_tag &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000780 verify(key, keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000781 return STAT_SECURE;
782 }
783 else
784 {
785 /* iterate through all possible keys 4035 5.3.1 */
786 for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000787 if (crecp->addr.key.algo == algo &&
788 crecp->addr.key.keytag == key_tag &&
Simon Kelley824202e2014-01-23 20:59:46 +0000789 crecp->uid == class &&
Simon Kelleyebe95a82014-02-13 14:56:10 +0000790 verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000791 return STAT_SECURE;
792 }
793 }
794
795 return STAT_BOGUS;
796}
797
Simon Kelley0fc2f312014-01-08 10:26:58 +0000798/* The DNS packet is expected to contain the answer to a DNSKEY query.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000799 Put all DNSKEYs in the answer which are valid into the cache.
800 return codes:
801 STAT_INSECURE bad packet, no DNSKEYs in reply.
802 STAT_SECURE At least one valid DNSKEY found and in cache.
Simon Kelley0fc2f312014-01-08 10:26:58 +0000803 STAT_BOGUS No DNSKEYs found, which can be validated with DS,
804 or self-sign for DNSKEY RRset is not valid.
805 STAT_NEED_DS DS records to validate a key not found, name in keyname
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000806*/
807int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
808{
Simon Kelley0fc2f312014-01-08 10:26:58 +0000809 unsigned char *psave, *p = (unsigned char *)(header+1);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000810 struct crec *crecp, *recp1;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000811 int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000812 struct blockdata *key;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000813 struct all_addr a;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000814
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000815 if (ntohs(header->qdcount) != 1 ||
816 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000817 return STAT_INSECURE;
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000818
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000819 GETSHORT(qtype, p);
820 GETSHORT(qclass, p);
821
Simon Kelley0fc2f312014-01-08 10:26:58 +0000822 if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000823 return STAT_INSECURE;
824
Simon Kelley0fc2f312014-01-08 10:26:58 +0000825 /* See if we have cached a DS record which validates this key */
826 if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
827 {
828 strcpy(keyname, name);
829 return STAT_NEED_DS;
830 }
831
Simon Kelley0fc2f312014-01-08 10:26:58 +0000832 /* NOTE, we need to find ONE DNSKEY which matches the DS */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000833 for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000834 {
835 /* Ensure we have type, class TTL and length */
Simon Kelley0fc2f312014-01-08 10:26:58 +0000836 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000837 return STAT_INSECURE; /* bad packet */
838
839 GETSHORT(qtype, p);
840 GETSHORT(qclass, p);
841 GETLONG(ttl, p);
842 GETSHORT(rdlen, p);
Simon Kelley6f468102014-01-26 23:39:17 +0000843
Simon Kelley0fc2f312014-01-08 10:26:58 +0000844 if (!CHECK_LEN(header, p, plen, rdlen) || rdlen < 4)
845 return STAT_INSECURE; /* bad packet */
846
Simon Kelley6f468102014-01-26 23:39:17 +0000847 if (qclass != class || qtype != T_DNSKEY || rc == 2)
848 {
849 p += rdlen;
850 continue;
851 }
852
Simon Kelley0fc2f312014-01-08 10:26:58 +0000853 psave = p;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000854
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000855 GETSHORT(flags, p);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000856 if (*p++ != 3)
857 return STAT_INSECURE;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000858 algo = *p++;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000859 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
Simon Kelleye7829ae2014-01-22 22:21:51 +0000860 key = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000861
Simon Kelleye7829ae2014-01-22 22:21:51 +0000862 /* key must have zone key flag set */
863 if (flags & 0x100)
864 key = blockdata_alloc((char*)p, rdlen - 4);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000865
866 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000867
Simon Kelley0fc2f312014-01-08 10:26:58 +0000868 if (!ADD_RDLEN(header, p, plen, rdlen))
Simon Kelley8d718cb2014-02-03 16:27:37 +0000869 {
870 if (key)
871 blockdata_free(key);
872 return STAT_INSECURE; /* bad packet */
873 }
874
Simon Kelleye7829ae2014-01-22 22:21:51 +0000875 /* No zone key flag or malloc failure */
876 if (!key)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000877 continue;
878
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +0000879 for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
Simon Kelley86bec2d2014-01-13 21:31:20 +0000880 {
881 void *ctx;
882 unsigned char *digest, *ds_digest;
883 const struct nettle_hash *hash;
884
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000885 if (recp1->addr.ds.algo == algo &&
886 recp1->addr.ds.keytag == keytag &&
Simon Kelley824202e2014-01-23 20:59:46 +0000887 recp1->uid == class &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000888 (hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
Simon Kelley86bec2d2014-01-13 21:31:20 +0000889 hash_init(hash, &ctx, &digest))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000890
Simon Kelley86bec2d2014-01-13 21:31:20 +0000891 {
892 int wire_len = to_wire(name);
893
894 /* Note that digest may be different between DSs, so
895 we can't move this outside the loop. */
896 hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name);
897 hash->update(ctx, (unsigned int)rdlen, psave);
898 hash->digest(ctx, hash->digest_size, digest);
899
900 from_wire(name);
901
Simon Kelley824202e2014-01-23 20:59:46 +0000902 if (recp1->addr.ds.keylen == (int)hash->digest_size &&
903 (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
904 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
Simon Kelleyf6a2b792014-02-01 14:54:26 +0000905 validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag) == STAT_SECURE)
Simon Kelley86bec2d2014-01-13 21:31:20 +0000906 {
Simon Kelley86bec2d2014-01-13 21:31:20 +0000907 valid = 1;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000908 break;
909 }
910 }
911 }
Simon Kelleye7829ae2014-01-22 22:21:51 +0000912 blockdata_free(key);
Simon Kelley0fc2f312014-01-08 10:26:58 +0000913 }
914
915 if (valid)
916 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000917 /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000918 cache_start_insert();
919
920 p = skip_questions(header, plen);
921
922 for (j = ntohs(header->ancount); j != 0; j--)
923 {
924 /* Ensure we have type, class TTL and length */
925 if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
926 return STAT_INSECURE; /* bad packet */
927
928 GETSHORT(qtype, p);
929 GETSHORT(qclass, p);
930 GETLONG(ttl, p);
931 GETSHORT(rdlen, p);
Simon Kelley8d718cb2014-02-03 16:27:37 +0000932
933 if (!CHECK_LEN(header, p, plen, rdlen))
Simon Kelleye7829ae2014-01-22 22:21:51 +0000934 return STAT_INSECURE; /* bad packet */
Simon Kelleye7829ae2014-01-22 22:21:51 +0000935
Simon Kelley8d718cb2014-02-03 16:27:37 +0000936 if (qclass == class && rc == 1)
Simon Kelleye7829ae2014-01-22 22:21:51 +0000937 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000938 psave = p;
Simon Kelleye7829ae2014-01-22 22:21:51 +0000939
Simon Kelley8d718cb2014-02-03 16:27:37 +0000940 if (qtype == T_DNSKEY)
941 {
942 if (rdlen < 4)
943 return STAT_INSECURE; /* bad packet */
944
945 GETSHORT(flags, p);
946 if (*p++ != 3)
947 return STAT_INSECURE;
948 algo = *p++;
949 keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
950
951 /* Cache needs to known class for DNSSEC stuff */
952 a.addr.dnssec.class = class;
953
954 if ((key = blockdata_alloc((char*)p, rdlen - 4)))
955 {
956 if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
957 blockdata_free(key);
958 else
959 {
960 a.addr.keytag = keytag;
961 log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
962
963 recp1->addr.key.keylen = rdlen - 4;
964 recp1->addr.key.keydata = key;
965 recp1->addr.key.algo = algo;
966 recp1->addr.key.keytag = keytag;
967 recp1->addr.key.flags = flags;
968 recp1->uid = class;
969 }
970 }
971 }
972 else if (qtype == T_RRSIG)
973 {
974 /* RRSIG, cache if covers DNSKEY RRset */
975 if (rdlen < 18)
976 return STAT_INSECURE; /* bad packet */
977
978 GETSHORT(type_covered, p);
979
980 if (type_covered == T_DNSKEY)
981 {
982 a.addr.dnssec.class = class;
983 a.addr.dnssec.type = type_covered;
984
985 algo = *p++;
986 p += 13; /* labels, orig_ttl, expiration, inception */
987 GETSHORT(keytag, p);
988 if ((key = blockdata_alloc((char*)psave, rdlen)))
989 {
990 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
991 blockdata_free(key);
992 else
993 {
994 crecp->uid = class;
995 crecp->addr.sig.keydata = key;
996 crecp->addr.sig.keylen = rdlen;
997 crecp->addr.sig.keytag = keytag;
998 crecp->addr.sig.type_covered = type_covered;
999 crecp->addr.sig.algo = algo;
1000 }
1001 }
1002 }
1003 }
Simon Kelleye7829ae2014-01-22 22:21:51 +00001004
Simon Kelley8d718cb2014-02-03 16:27:37 +00001005 p = psave;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001006 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001007
Simon Kelleye7829ae2014-01-22 22:21:51 +00001008 if (!ADD_RDLEN(header, p, plen, rdlen))
1009 return STAT_INSECURE; /* bad packet */
1010 }
1011
Simon Kelley0fc2f312014-01-08 10:26:58 +00001012 /* commit cache insert. */
1013 cache_end_insert();
1014 return STAT_SECURE;
1015 }
1016
1017 log_query(F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
1018 return STAT_BOGUS;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001019}
Simon Kelley0fc2f312014-01-08 10:26:58 +00001020
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001021/* The DNS packet is expected to contain the answer to a DS query
1022 Put all DSs in the answer which are valid into the cache.
1023 return codes:
Simon Kelley0fc2f312014-01-08 10:26:58 +00001024 STAT_INSECURE bad packet, no DS in reply.
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001025 STAT_SECURE At least one valid DS found and in cache.
1026 STAT_BOGUS At least one DS found, which fails validation.
1027 STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
1028*/
1029
1030int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
1031{
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001032 unsigned char *p = (unsigned char *)(header+1);
1033 int qtype, qclass, val;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001034
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001035 if (ntohs(header->qdcount) != 1 ||
1036 !extract_name(header, plen, &p, name, 1, 4))
Simon Kelley8d718cb2014-02-03 16:27:37 +00001037 return STAT_INSECURE;
1038
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001039 GETSHORT(qtype, p);
1040 GETSHORT(qclass, p);
1041
Simon Kelley0fc2f312014-01-08 10:26:58 +00001042 if (qtype != T_DS || qclass != class || ntohs(header->ancount) == 0)
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001043 return STAT_INSECURE;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001044
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001045 val = dnssec_validate_reply(now, header, plen, name, keyname, NULL);
1046
Simon Kelley0fc2f312014-01-08 10:26:58 +00001047 if (val == STAT_BOGUS)
Simon Kelley8d718cb2014-02-03 16:27:37 +00001048 {
1049 p = (unsigned char *)(header+1);
1050 extract_name(header, plen, &p, name, 1, 4);
1051 log_query(F_UPSTREAM, name, NULL, "BOGUS DS");
1052 }
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001053
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001054 return val;
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001055}
1056
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001057/* 4034 6.1 */
1058static int hostname_cmp(const char *a, const char *b)
1059{
Simon Kelleydbf72122014-01-21 14:28:02 +00001060 char *sa, *ea, *ca, *sb, *eb, *cb;
1061 unsigned char ac, bc;
1062
1063 sa = ea = (char *)a + strlen(a);
1064 sb = eb = (char *)b + strlen(b);
1065
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001066 while (1)
1067 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001068 while (sa != a && *(sa-1) != '.')
1069 sa--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001070
Simon Kelleydbf72122014-01-21 14:28:02 +00001071 while (sb != b && *(sb-1) != '.')
1072 sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001073
Simon Kelleydbf72122014-01-21 14:28:02 +00001074 ca = sa;
1075 cb = sb;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001076
Simon Kelleydbf72122014-01-21 14:28:02 +00001077 while (1)
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001078 {
Simon Kelleydbf72122014-01-21 14:28:02 +00001079 if (ca == ea)
1080 {
1081 if (cb == eb)
1082 break;
1083
1084 return -1;
1085 }
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001086
Simon Kelleydbf72122014-01-21 14:28:02 +00001087 if (cb == eb)
1088 return 1;
1089
1090 ac = (unsigned char) *ca++;
1091 bc = (unsigned char) *cb++;
1092
1093 if (ac >= 'A' && ac <= 'Z')
1094 ac += 'a' - 'A';
1095 if (bc >= 'A' && bc <= 'Z')
1096 bc += 'a' - 'A';
1097
Simon Kelley979cdf92014-01-21 16:26:41 +00001098 if (ac < bc)
Simon Kelleydbf72122014-01-21 14:28:02 +00001099 return -1;
1100 else if (ac != bc)
1101 return 1;
1102 }
1103
1104
1105 if (sa == a)
1106 {
1107 if (sb == b)
1108 return 0;
1109
1110 return -1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001111 }
1112
Simon Kelleydbf72122014-01-21 14:28:02 +00001113 if (sb == b)
1114 return 1;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001115
Simon Kelleydbf72122014-01-21 14:28:02 +00001116 ea = sa--;
1117 eb = sb--;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001118 }
1119}
1120
1121
Simon Kelley0fc2f312014-01-08 10:26:58 +00001122/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001123/* Returns are the same as validate_rrset, plus the class if the missing key is in *class */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001124int 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 +02001125{
Simon Kelley0fc2f312014-01-08 10:26:58 +00001126 unsigned char *ans_start, *p1, *p2;
1127 int type1, class1, rdlen1, type2, class2, rdlen2;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001128 int i, j, rc, have_nsec, have_nsec_equal, cname_count = 5;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001129
Simon Kelleye3ec15a2014-02-13 16:56:30 +00001130 if (RCODE(header) == SERVFAIL)
1131 return STAT_BOGUS;
1132
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001133 if ((RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR) || ntohs(header->qdcount) != 1)
Simon Kelley72ae2f32014-01-19 09:54:16 +00001134 return STAT_INSECURE;
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001135
Simon Kelley0fc2f312014-01-08 10:26:58 +00001136 if (!(ans_start = skip_questions(header, plen)))
1137 return STAT_INSECURE;
1138
1139 for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
Giovanni Bajoe292e932012-04-22 14:32:02 +02001140 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001141 if (!extract_name(header, plen, &p1, name, 1, 10))
1142 return STAT_INSECURE; /* bad packet */
1143
1144 GETSHORT(type1, p1);
1145 GETSHORT(class1, p1);
1146 p1 += 4; /* TTL */
1147 GETSHORT(rdlen1, p1);
1148
1149 /* Don't try and validate RRSIGs! */
1150 if (type1 != T_RRSIG)
1151 {
1152 /* Check if we've done this RRset already */
1153 for (p2 = ans_start, j = 0; j < i; j++)
1154 {
1155 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1156 return STAT_INSECURE; /* bad packet */
1157
1158 GETSHORT(type2, p2);
1159 GETSHORT(class2, p2);
1160 p2 += 4; /* TTL */
1161 GETSHORT(rdlen2, p2);
1162
1163 if (type2 == type1 && class2 == class1 && rc == 1)
1164 break; /* Done it before: name, type, class all match. */
1165
1166 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1167 return STAT_INSECURE;
1168 }
1169
1170 /* Not done, validate now */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001171 if (j == i)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001172 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001173 int ttl, keytag, algo, digest, type_covered;
1174 unsigned char *psave;
1175 struct all_addr a;
1176 struct blockdata *key;
1177 struct crec *crecp;
1178
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001179 if ((rc = validate_rrset(now, header, plen, class1, type1, name, keyname, NULL, 0, 0, 0)) != STAT_SECURE)
1180 {
1181 if (class)
1182 *class = class1; /* Class for DS or DNSKEY */
1183 return rc;
1184 }
1185
Simon Kelley8d718cb2014-02-03 16:27:37 +00001186 /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
1187 cache_start_insert();
1188
1189 for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001190 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001191 if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
1192 return STAT_INSECURE; /* bad packet */
1193
1194 GETSHORT(type2, p2);
1195 GETSHORT(class2, p2);
1196 GETLONG(ttl, p2);
1197 GETSHORT(rdlen2, p2);
1198
1199 if (!CHECK_LEN(header, p2, plen, rdlen2))
1200 return STAT_INSECURE; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001201
Simon Kelley8d718cb2014-02-03 16:27:37 +00001202 if (class2 == class1 && rc == 1)
1203 {
1204 psave = p2;
1205
1206 if (type1 == T_DS && type2 == T_DS)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001207 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001208 if (rdlen2 < 4)
1209 return STAT_INSECURE; /* bad packet */
1210
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001211 GETSHORT(keytag, p2);
1212 algo = *p2++;
1213 digest = *p2++;
1214
1215 /* Cache needs to known class for DNSSEC stuff */
1216 a.addr.dnssec.class = class2;
1217
Simon Kelley8d718cb2014-02-03 16:27:37 +00001218 if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001219 {
Simon Kelley8d718cb2014-02-03 16:27:37 +00001220 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
1221 blockdata_free(key);
1222 else
1223 {
1224 a.addr.keytag = keytag;
1225 log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
1226 crecp->addr.ds.digest = digest;
1227 crecp->addr.ds.keydata = key;
1228 crecp->addr.ds.algo = algo;
1229 crecp->addr.ds.keytag = keytag;
1230 crecp->uid = class2;
1231 crecp->addr.ds.keylen = rdlen2 - 4;
1232 }
1233 }
1234 }
1235 else if (type2 == T_RRSIG)
1236 {
1237 if (rdlen2 < 18)
1238 return STAT_INSECURE; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001239
Simon Kelley8d718cb2014-02-03 16:27:37 +00001240 GETSHORT(type_covered, p2);
1241
1242 if (type_covered == type1 &&
1243 (type_covered == T_A || type_covered == T_AAAA ||
1244 type_covered == T_CNAME || type_covered == T_DS ||
1245 type_covered == T_DNSKEY || type_covered == T_PTR))
1246 {
1247 a.addr.dnssec.type = type_covered;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001248 a.addr.dnssec.class = class1;
Simon Kelley8d718cb2014-02-03 16:27:37 +00001249
1250 algo = *p2++;
1251 p2 += 13; /* labels, orig_ttl, expiration, inception */
1252 GETSHORT(keytag, p2);
1253
1254 if ((key = blockdata_alloc((char*)psave, rdlen2)))
1255 {
1256 if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
1257 blockdata_free(key);
1258 else
1259 {
1260 crecp->uid = class1;
1261 crecp->addr.sig.keydata = key;
1262 crecp->addr.sig.keylen = rdlen2;
1263 crecp->addr.sig.keytag = keytag;
1264 crecp->addr.sig.type_covered = type_covered;
1265 crecp->addr.sig.algo = algo;
1266 }
1267 }
1268 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001269 }
1270
Simon Kelley8d718cb2014-02-03 16:27:37 +00001271 p2 = psave;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001272 }
1273
Simon Kelley8d718cb2014-02-03 16:27:37 +00001274 if (!ADD_RDLEN(header, p2, plen, rdlen2))
1275 return STAT_INSECURE; /* bad packet */
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001276 }
Simon Kelley8d718cb2014-02-03 16:27:37 +00001277
1278 cache_end_insert();
Simon Kelley0fc2f312014-01-08 10:26:58 +00001279 }
1280 }
1281
1282 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1283 return STAT_INSECURE;
Giovanni Bajoe292e932012-04-22 14:32:02 +02001284 }
1285
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001286 /* OK, all the RRsets validate, now see if we have a NODATA or NXDOMAIN reply */
1287
1288 p1 = (unsigned char *)(header+1);
1289
1290 if (!extract_name(header, plen, &p1, name, 1, 4))
1291 return STAT_INSECURE;
1292
1293 GETSHORT(type1, p1);
1294 GETSHORT(class1, p1);
1295
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001296 /* Can't validate RRSIG query */
1297 if (type1 == T_RRSIG)
1298 return STAT_INSECURE;
1299
Simon Kelleyc5f4ec72014-01-20 22:37:55 +00001300 cname_loop:
1301 for (j = ntohs(header->ancount); j != 0; j--)
1302 {
1303 if (!(rc = extract_name(header, plen, &p1, name, 0, 10)))
1304 return STAT_INSECURE; /* bad packet */
1305
1306 GETSHORT(type2, p1);
1307 GETSHORT(class2, p1);
1308 p1 += 4; /* TTL */
1309 GETSHORT(rdlen2, p1);
1310
1311 if (rc == 1 && class1 == class2)
1312 {
1313 /* Do we have an answer for the question? */
1314 if (type1 == type2)
1315 return RCODE(header) == NXDOMAIN ? STAT_INSECURE : STAT_SECURE;
1316 else if (type2 == T_CNAME)
1317 {
1318 /* looped CNAMES */
1319 if (!cname_count-- ||
1320 !extract_name(header, plen, &p1, name, 1, 0) ||
1321 !(p1 = skip_questions(header, plen)))
1322 return STAT_INSECURE;
1323
1324 goto cname_loop;
1325 }
1326 }
1327
1328 if (!ADD_RDLEN(header, p1, plen, rdlen2))
1329 return STAT_INSECURE;
1330 }
1331
1332 /* NXDOMAIN or NODATA reply, look for NSEC records to support that.
1333 At this point, p1 points to the start of the auth section.
1334 Use keyname as workspace */
1335 for (have_nsec = 0, have_nsec_equal = 0, p2 = NULL, rdlen2 = 0, j = ntohs(header->nscount); j != 0; j--)
1336 {
1337 unsigned char *nsec_start = p1;
1338 if (!extract_name(header, plen, &p1, keyname, 1, 10))
1339 return STAT_INSECURE; /* bad packet */
1340
1341 GETSHORT(type2, p1);
1342 GETSHORT(class2, p1);
1343 p1 += 4; /* TTL */
1344 GETSHORT(rdlen1, p1);
1345
1346 if (class1 == class2 && type2 == T_NSEC)
1347 {
1348 have_nsec = 1;
1349 rc = hostname_cmp(name, keyname);
1350
1351 if (rc >= 0)
1352 {
1353 if (p2)
1354 {
1355 unsigned char *psave = p2;
1356 /* new NSEC is smaller than name,
1357 is it bigger than previous one? */
1358
1359 /* get previous one into name buffer */
1360 if (!extract_name(header, plen, &psave, name, 1, 0))
1361 return STAT_INSECURE; /* bad packet */
1362
1363 if (hostname_cmp(name, keyname) < 0)
1364 {
1365 p2 = nsec_start;
1366 rdlen2 = rdlen1;
1367 }
1368
1369 /* restore query name */
1370 psave = (unsigned char *)(header+1);
1371 if (!extract_name(header, plen, &psave, name, 1, 0))
1372 return STAT_INSECURE;
1373 }
1374 else
1375 {
1376 /* There was no previous best candidate */
1377 p2 = nsec_start;
1378 rdlen2 = rdlen1;
1379 }
1380 }
1381
1382 if (rc == 0)
1383 have_nsec_equal = 1;
1384 }
1385
1386 if (!ADD_RDLEN(header, p1, plen, rdlen1))
1387 return STAT_INSECURE;
1388 }
1389
1390
1391 if (p2)
1392 {
1393 unsigned char *psave;
1394 p2 = skip_name(p2, header, plen, 0);
1395 p2 += 10; /* type, class, ttl, rdlen */
1396 psave = p2;
1397 extract_name(header, plen, &p2, keyname, 1, 0);
1398 rdlen2 -= p2 - psave;
1399 }
1400
1401 /* At this point, have_nsec is set if there's at least one NSEC
1402 have_nsec_equal is set if there's an NSEC with the same name as the query;
1403 p2 points to the type bit maps of the biggest NSEC smaller than or equal to the query
1404 or NULL if the query is smaller than all of them.
1405 Keyname holds the next domain name for that NSEC.
1406 rdlen2 is the length of the bitmap field */
1407
1408
1409 if (RCODE(header) == NOERROR && have_nsec_equal)
1410 {
1411 int offset = (type1 & 0xff) >> 3;
1412 int mask = 0x80 >> (type1 & 0x07);
1413
1414 while (rdlen2 >= 2)
1415 {
1416 if (p2[0] == type1 >> 8)
1417 {
1418 /* Does the NSEC say our type exists? */
1419 if (offset < p2[1] &&
1420 (p2[offset+2] & mask) != 0)
1421 return STAT_INSECURE;
1422
1423 break; /* finshed checking */
1424 }
1425
1426 rdlen2 -= p2[1];
1427 p2 += p2[1];
1428 }
1429
1430 return STAT_SECURE;
1431 }
1432
1433 if (RCODE(header) == NXDOMAIN && have_nsec)
1434 {
1435 if (!p2 || hostname_cmp(name, keyname) < 0)
1436 return STAT_SECURE; /* Before the first, or in a proven gap */
1437 }
1438
1439 return STAT_INSECURE;
Giovanni Bajoadca3e92012-04-25 17:46:53 +02001440}
1441
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +00001442
Giovanni Bajo3471f182012-04-25 17:49:16 +02001443/* Compute keytag (checksum to quickly index a key). See RFC4034 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001444int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
Giovanni Bajo3471f182012-04-25 17:49:16 +02001445{
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001446 if (alg == 1)
1447 {
1448 /* Algorithm 1 (RSAMD5) has a different (older) keytag calculation algorithm.
1449 See RFC4034, Appendix B.1 */
Simon Kelley0fc2f312014-01-08 10:26:58 +00001450 return key[keylen-4] * 256 + key[keylen-3];
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001451 }
1452 else
1453 {
Simon Kelley1633e302014-02-10 16:42:46 +00001454 unsigned long ac = flags + 0x300 + alg;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001455 int i;
Giovanni Bajo3471f182012-04-25 17:49:16 +02001456
Simon Kelley0fc2f312014-01-08 10:26:58 +00001457 for (i = 0; i < keylen; ++i)
1458 ac += (i & 1) ? key[i] : key[i] << 8;
Simon Kelley1633e302014-02-10 16:42:46 +00001459
Simon Kelley0fc2f312014-01-08 10:26:58 +00001460 ac += (ac >> 16) & 0xffff;
1461 return ac & 0xffff;
Giovanni Bajo75ffc9b2012-05-02 19:58:06 +02001462 }
Giovanni Bajo3471f182012-04-25 17:49:16 +02001463}
1464
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001465size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr)
1466{
1467 unsigned char *p;
Simon Kelley610e7822014-02-06 14:45:17 +00001468 char *types = querystr("dnssec-query", type);
Giovanni Bajo0304d282012-05-02 03:29:52 +02001469
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001470 if (addr->sa.sa_family == AF_INET)
1471 log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
1472#ifdef HAVE_IPV6
1473 else
1474 log_query(F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
1475#endif
1476
1477 header->qdcount = htons(1);
1478 header->ancount = htons(0);
1479 header->nscount = htons(0);
1480 header->arcount = htons(0);
1481
1482 header->hb3 = HB3_RD;
1483 SET_OPCODE(header, QUERY);
Simon Kelley5b3bf922014-01-25 17:03:07 +00001484 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1485 this allows it to select auth servers when one is returning bad data. */
1486 header->hb4 = option_bool(OPT_DNSSEC_DEBUG) ? HB4_CD : 0;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001487
1488 /* ID filled in later */
1489
1490 p = (unsigned char *)(header+1);
1491
1492 p = do_rfc1035_name(p, name);
1493 *p++ = 0;
1494 PUTSHORT(type, p);
1495 PUTSHORT(class, p);
1496
1497 return add_do_bit(header, p - (unsigned char *)header, end);
1498}
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001499
1500unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
1501{
1502 int q;
1503 unsigned int len;
1504 unsigned char *p = (unsigned char *)(header+1);
1505 const struct nettle_hash *hash;
1506 void *ctx;
1507 unsigned char *digest;
Simon Kelley5f8e58f2014-01-09 17:31:19 +00001508
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001509 if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
1510 return NULL;
1511
1512 for (q = ntohs(header->qdcount); q != 0; q--)
1513 {
1514 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley7d23a662014-01-26 09:33:21 +00001515 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001516
1517 len = to_wire(name);
1518 hash->update(ctx, len, (unsigned char *)name);
1519 /* CRC the class and type as well */
1520 hash->update(ctx, 4, p);
1521
1522 p += 4;
1523 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley7d23a662014-01-26 09:33:21 +00001524 break; /* bad packet */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001525 }
Simon Kelley703c7ff2014-01-25 23:46:23 +00001526
1527 hash->digest(ctx, hash->digest_size, digest);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001528 return digest;
1529}
1530
Simon Kelley0fc2f312014-01-08 10:26:58 +00001531#endif /* HAVE_DNSSEC */