bind - Removed version tag from contrib directory and updated README.DRAGONFLY.
[dragonfly.git] / contrib / bind / lib / bind / nameser / ns_verify.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1999 by Internet Software Consortium, Inc.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #ifndef lint
19 static const char rcsid[] = "$Id: ns_verify.c,v 1.5 2006/03/09 23:57:56 marka Exp $";
20 #endif
21
22 /* Import. */
23
24 #include "port_before.h"
25 #include "fd_setsize.h"
26
27 #include <sys/types.h>
28 #include <sys/param.h>
29
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
32 #include <arpa/inet.h>
33
34 #include <errno.h>
35 #include <netdb.h>
36 #include <resolv.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <unistd.h>
42
43 #include <isc/dst.h>
44
45 #include "port_after.h"
46
47 /* Private. */
48
49 #define BOUNDS_CHECK(ptr, count) \
50         do { \
51                 if ((ptr) + (count) > eom) { \
52                         return (NS_TSIG_ERROR_FORMERR); \
53                 } \
54         } while (0)
55
56 /* Public. */
57
58 u_char *
59 ns_find_tsig(u_char *msg, u_char *eom) {
60         HEADER *hp = (HEADER *)msg;
61         int n, type;
62         u_char *cp = msg, *start;
63
64         if (msg == NULL || eom == NULL || msg > eom)
65                 return (NULL);
66
67         if (cp + HFIXEDSZ >= eom)
68                 return (NULL);
69
70         if (hp->arcount == 0)
71                 return (NULL);
72
73         cp += HFIXEDSZ;
74
75         n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
76         if (n < 0)
77                 return (NULL);
78         cp += n;
79
80         n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
81         if (n < 0)
82                 return (NULL);
83         cp += n;
84
85         n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
86         if (n < 0)
87                 return (NULL);
88         cp += n;
89
90         n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1);
91         if (n < 0)
92                 return (NULL);
93         cp += n;
94
95         start = cp;
96         n = dn_skipname(cp, eom);
97         if (n < 0)
98                 return (NULL);
99         cp += n;
100         if (cp + INT16SZ >= eom)
101                 return (NULL);
102
103         GETSHORT(type, cp);
104         if (type != ns_t_tsig)
105                 return (NULL);
106         return (start);
107 }
108
109 /* ns_verify
110  *
111  * Parameters:
112  *\li   statp           res stuff
113  *\li   msg             received message
114  *\li   msglen          length of message
115  *\li   key             tsig key used for verifying.
116  *\li   querysig        (response), the signature in the query
117  *\li   querysiglen     (response), the length of the signature in the query
118  *\li   sig             (query), a buffer to hold the signature
119  *\li   siglen          (query), input - length of signature buffer
120  *                               output - length of signature
121  *
122  * Errors:
123  *\li   - bad input (-1)
124  *\li   - invalid dns message (NS_TSIG_ERROR_FORMERR)
125  *\li   - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
126  *\li   - key doesn't match (-ns_r_badkey)
127  *\li   - TSIG verification fails with BADKEY (-ns_r_badkey)
128  *\li   - TSIG verification fails with BADSIG (-ns_r_badsig)
129  *\li   - TSIG verification fails with BADTIME (-ns_r_badtime)
130  *\li   - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
131  *\li   - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
132  *\li   - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
133  */
134 int
135 ns_verify(u_char *msg, int *msglen, void *k,
136           const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
137           time_t *timesigned, int nostrip)
138 {
139         HEADER *hp = (HEADER *)msg;
140         DST_KEY *key = (DST_KEY *)k;
141         u_char *cp = msg, *eom;
142         char name[MAXDNAME], alg[MAXDNAME];
143         u_char *recstart, *rdatastart;
144         u_char *sigstart, *otherstart;
145         int n;
146         int error;
147         u_int16_t type, length;
148         u_int16_t fudge, sigfieldlen, otherfieldlen;
149
150         dst_init();
151         if (msg == NULL || msglen == NULL || *msglen < 0)
152                 return (-1);
153
154         eom = msg + *msglen;
155
156         recstart = ns_find_tsig(msg, eom);
157         if (recstart == NULL)
158                 return (NS_TSIG_ERROR_NO_TSIG);
159
160         cp = recstart;
161
162         /* Read the key name. */
163         n = dn_expand(msg, eom, cp, name, MAXDNAME);
164         if (n < 0)
165                 return (NS_TSIG_ERROR_FORMERR);
166         cp += n;
167
168         /* Read the type. */
169         BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
170         GETSHORT(type, cp);
171         if (type != ns_t_tsig)
172                 return (NS_TSIG_ERROR_NO_TSIG);
173
174         /* Skip the class and TTL, save the length. */
175         cp += INT16SZ + INT32SZ;
176         GETSHORT(length, cp);
177         if (eom - cp != length)
178                 return (NS_TSIG_ERROR_FORMERR);
179
180         /* Read the algorithm name. */
181         rdatastart = cp;
182         n = dn_expand(msg, eom, cp, alg, MAXDNAME);
183         if (n < 0)
184                 return (NS_TSIG_ERROR_FORMERR);
185         if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
186                 return (-ns_r_badkey);
187         cp += n;
188
189         /* Read the time signed and fudge. */
190         BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
191         cp += INT16SZ;
192         GETLONG((*timesigned), cp);
193         GETSHORT(fudge, cp);
194
195         /* Read the signature. */
196         BOUNDS_CHECK(cp, INT16SZ);
197         GETSHORT(sigfieldlen, cp);
198         BOUNDS_CHECK(cp, sigfieldlen);
199         sigstart = cp;
200         cp += sigfieldlen;
201
202         /* Skip id and read error. */
203         BOUNDS_CHECK(cp, 2*INT16SZ);
204         cp += INT16SZ;
205         GETSHORT(error, cp);
206
207         /* Parse the other data. */
208         BOUNDS_CHECK(cp, INT16SZ);
209         GETSHORT(otherfieldlen, cp);
210         BOUNDS_CHECK(cp, otherfieldlen);
211         otherstart = cp;
212         cp += otherfieldlen;
213
214         if (cp != eom)
215                 return (NS_TSIG_ERROR_FORMERR);
216
217         /* Verify that the key used is OK. */
218         if (key != NULL) {
219                 if (key->dk_alg != KEY_HMAC_MD5)
220                         return (-ns_r_badkey);
221                 if (error != ns_r_badsig && error != ns_r_badkey) {
222                         if (ns_samename(key->dk_key_name, name) != 1)
223                                 return (-ns_r_badkey);
224                 }
225         }
226
227         hp->arcount = htons(ntohs(hp->arcount) - 1);
228
229         /*
230          * Do the verification.
231          */
232
233         if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
234                 void *ctx;
235                 u_char buf[MAXDNAME];
236                 u_char buf2[MAXDNAME];
237
238                 /* Digest the query signature, if this is a response. */
239                 dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
240                 if (querysiglen > 0 && querysig != NULL) {
241                         u_int16_t len_n = htons(querysiglen);
242                         dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
243                                         (u_char *)&len_n, INT16SZ, NULL, 0);
244                         dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
245                                         querysig, querysiglen, NULL, 0);
246                 }
247                 
248                 /* Digest the message. */
249                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg,
250                                 NULL, 0);
251
252                 /* Digest the key name. */
253                 n = ns_name_pton(name, buf2, sizeof(buf2));
254                 if (n < 0)
255                         return (-1);
256                 n = ns_name_ntol(buf2, buf, sizeof(buf));
257                 if (n < 0)
258                         return (-1);
259                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
260
261                 /* Digest the class and TTL. */
262                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
263                                 recstart + dn_skipname(recstart, eom) + INT16SZ,
264                                 INT16SZ + INT32SZ, NULL, 0);
265
266                 /* Digest the algorithm. */
267                 n = ns_name_pton(alg, buf2, sizeof(buf2));
268                 if (n < 0)
269                         return (-1);
270                 n = ns_name_ntol(buf2, buf, sizeof(buf));
271                 if (n < 0)
272                         return (-1);
273                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
274
275                 /* Digest the time signed and fudge. */
276                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
277                                 rdatastart + dn_skipname(rdatastart, eom),
278                                 INT16SZ + INT32SZ + INT16SZ, NULL, 0);
279
280                 /* Digest the error and other data. */
281                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
282                                 otherstart - INT16SZ - INT16SZ,
283                                 otherfieldlen + INT16SZ + INT16SZ, NULL, 0);
284
285                 n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
286                                     sigstart, sigfieldlen);
287
288                 if (n < 0)
289                         return (-ns_r_badsig);
290
291                 if (sig != NULL && siglen != NULL) {
292                         if (*siglen < sigfieldlen)
293                                 return (NS_TSIG_ERROR_NO_SPACE);
294                         memcpy(sig, sigstart, sigfieldlen);
295                         *siglen = sigfieldlen;
296                 }
297         } else {
298                 if (sigfieldlen > 0)
299                         return (NS_TSIG_ERROR_FORMERR);
300                 if (sig != NULL && siglen != NULL)
301                         *siglen = 0;
302         }
303
304         /* Reset the counter, since we still need to check for badtime. */
305         hp->arcount = htons(ntohs(hp->arcount) + 1);
306
307         /* Verify the time. */
308         if (abs((*timesigned) - time(NULL)) > fudge)
309                 return (-ns_r_badtime);
310
311         if (nostrip == 0) {
312                 *msglen = recstart - msg;
313                 hp->arcount = htons(ntohs(hp->arcount) - 1);
314         }
315
316         if (error != NOERROR)
317                 return (error);
318
319         return (0);
320 }
321
322 int
323 ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen,
324                    ns_tcp_tsig_state *state)
325 {
326         dst_init();
327         if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
328                 return (-1);
329         state->counter = -1;
330         state->key = k;
331         if (state->key->dk_alg != KEY_HMAC_MD5)
332                 return (-ns_r_badkey);
333         if (querysiglen > (int)sizeof(state->sig))
334                 return (-1);
335         memcpy(state->sig, querysig, querysiglen);
336         state->siglen = querysiglen;
337         return (0);
338 }
339
340 int
341 ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state,
342               int required)
343 {
344         HEADER *hp = (HEADER *)msg;
345         u_char *recstart, *sigstart;
346         unsigned int sigfieldlen, otherfieldlen;
347         u_char *cp, *eom, *cp2;
348         char name[MAXDNAME], alg[MAXDNAME];
349         u_char buf[MAXDNAME];
350         int n, type, length, fudge, error;
351         time_t timesigned;
352
353         if (msg == NULL || msglen == NULL || state == NULL)
354                 return (-1);
355
356         eom = msg + *msglen;
357
358         state->counter++;
359         if (state->counter == 0)
360                 return (ns_verify(msg, msglen, state->key,
361                                   state->sig, state->siglen,
362                                   state->sig, &state->siglen, &timesigned, 0));
363
364         if (state->siglen > 0) {
365                 u_int16_t siglen_n = htons(state->siglen);
366
367                 dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
368                                 NULL, 0, NULL, 0);
369                 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
370                                 (u_char *)&siglen_n, INT16SZ, NULL, 0);
371                 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
372                                 state->sig, state->siglen, NULL, 0);
373                 state->siglen = 0;
374         }
375
376         cp = recstart = ns_find_tsig(msg, eom);
377
378         if (recstart == NULL) {
379                 if (required)
380                         return (NS_TSIG_ERROR_NO_TSIG);
381                 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
382                                 msg, *msglen, NULL, 0);
383                 return (0);
384         }
385
386         hp->arcount = htons(ntohs(hp->arcount) - 1);
387         dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
388                         msg, recstart - msg, NULL, 0);
389         
390         /* Read the key name. */
391         n = dn_expand(msg, eom, cp, name, MAXDNAME);
392         if (n < 0)
393                 return (NS_TSIG_ERROR_FORMERR);
394         cp += n;
395
396         /* Read the type. */
397         BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
398         GETSHORT(type, cp);
399         if (type != ns_t_tsig)
400                 return (NS_TSIG_ERROR_NO_TSIG);
401
402         /* Skip the class and TTL, save the length. */
403         cp += INT16SZ + INT32SZ;
404         GETSHORT(length, cp);
405         if (eom - cp != length)
406                 return (NS_TSIG_ERROR_FORMERR);
407
408         /* Read the algorithm name. */
409         n = dn_expand(msg, eom, cp, alg, MAXDNAME);
410         if (n < 0)
411                 return (NS_TSIG_ERROR_FORMERR);
412         if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
413                 return (-ns_r_badkey);
414         cp += n;
415
416         /* Verify that the key used is OK. */
417         if ((ns_samename(state->key->dk_key_name, name) != 1 ||
418              state->key->dk_alg != KEY_HMAC_MD5))
419                 return (-ns_r_badkey);
420
421         /* Read the time signed and fudge. */
422         BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
423         cp += INT16SZ;
424         GETLONG(timesigned, cp);
425         GETSHORT(fudge, cp);
426
427         /* Read the signature. */
428         BOUNDS_CHECK(cp, INT16SZ);
429         GETSHORT(sigfieldlen, cp);
430         BOUNDS_CHECK(cp, sigfieldlen);
431         sigstart = cp;
432         cp += sigfieldlen;
433
434         /* Skip id and read error. */
435         BOUNDS_CHECK(cp, 2*INT16SZ);
436         cp += INT16SZ;
437         GETSHORT(error, cp);
438
439         /* Parse the other data. */
440         BOUNDS_CHECK(cp, INT16SZ);
441         GETSHORT(otherfieldlen, cp);
442         BOUNDS_CHECK(cp, otherfieldlen);
443         cp += otherfieldlen;
444
445         if (cp != eom)
446                 return (NS_TSIG_ERROR_FORMERR);
447
448         /*
449          * Do the verification.
450          */
451
452         /* Digest the time signed and fudge. */
453         cp2 = buf;
454         PUTSHORT(0, cp2);       /*%< Top 16 bits of time. */
455         PUTLONG(timesigned, cp2);
456         PUTSHORT(NS_TSIG_FUDGE, cp2);
457
458         dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
459                         buf, cp2 - buf, NULL, 0);
460
461         n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
462                             sigstart, sigfieldlen);
463         if (n < 0)
464                 return (-ns_r_badsig);
465
466         if (sigfieldlen > sizeof(state->sig))
467                 return (NS_TSIG_ERROR_NO_SPACE);
468
469         memcpy(state->sig, sigstart, sigfieldlen);
470         state->siglen = sigfieldlen;
471
472         /* Verify the time. */
473         if (abs(timesigned - time(NULL)) > fudge)
474                 return (-ns_r_badtime);
475
476         *msglen = recstart - msg;
477
478         if (error != NOERROR)
479                 return (error);
480
481         return (0);
482 }
483
484 /*! \file */