Merge from vendor branch OPENSSL:
[dragonfly.git] / contrib / bind-9.3 / 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.1.206.3 2006/03/10 00:17:21 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  * Parameters:
111  *      statp           res stuff
112  *      msg             received message
113  *      msglen          length of message
114  *      key             tsig key used for verifying.
115  *      querysig        (response), the signature in the query
116  *      querysiglen     (response), the length of the signature in the query
117  *      sig             (query), a buffer to hold the signature
118  *      siglen          (query), input - length of signature buffer
119  *                               output - length of signature
120  *
121  * Errors:
122  *      - bad input (-1)
123  *      - invalid dns message (NS_TSIG_ERROR_FORMERR)
124  *      - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
125  *      - key doesn't match (-ns_r_badkey)
126  *      - TSIG verification fails with BADKEY (-ns_r_badkey)
127  *      - TSIG verification fails with BADSIG (-ns_r_badsig)
128  *      - TSIG verification fails with BADTIME (-ns_r_badtime)
129  *      - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
130  *      - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
131  *      - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
132  */
133 int
134 ns_verify(u_char *msg, int *msglen, void *k,
135           const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
136           time_t *timesigned, int nostrip)
137 {
138         HEADER *hp = (HEADER *)msg;
139         DST_KEY *key = (DST_KEY *)k;
140         u_char *cp = msg, *eom;
141         char name[MAXDNAME], alg[MAXDNAME];
142         u_char *recstart, *rdatastart;
143         u_char *sigstart, *otherstart;
144         int n;
145         int error;
146         u_int16_t type, length;
147         u_int16_t fudge, sigfieldlen, otherfieldlen;
148
149         dst_init();
150         if (msg == NULL || msglen == NULL || *msglen < 0)
151                 return (-1);
152
153         eom = msg + *msglen;
154
155         recstart = ns_find_tsig(msg, eom);
156         if (recstart == NULL)
157                 return (NS_TSIG_ERROR_NO_TSIG);
158
159         cp = recstart;
160
161         /* Read the key name. */
162         n = dn_expand(msg, eom, cp, name, MAXDNAME);
163         if (n < 0)
164                 return (NS_TSIG_ERROR_FORMERR);
165         cp += n;
166
167         /* Read the type. */
168         BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
169         GETSHORT(type, cp);
170         if (type != ns_t_tsig)
171                 return (NS_TSIG_ERROR_NO_TSIG);
172
173         /* Skip the class and TTL, save the length. */
174         cp += INT16SZ + INT32SZ;
175         GETSHORT(length, cp);
176         if (eom - cp != length)
177                 return (NS_TSIG_ERROR_FORMERR);
178
179         /* Read the algorithm name. */
180         rdatastart = cp;
181         n = dn_expand(msg, eom, cp, alg, MAXDNAME);
182         if (n < 0)
183                 return (NS_TSIG_ERROR_FORMERR);
184         if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
185                 return (-ns_r_badkey);
186         cp += n;
187
188         /* Read the time signed and fudge. */
189         BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
190         cp += INT16SZ;
191         GETLONG((*timesigned), cp);
192         GETSHORT(fudge, cp);
193
194         /* Read the signature. */
195         BOUNDS_CHECK(cp, INT16SZ);
196         GETSHORT(sigfieldlen, cp);
197         BOUNDS_CHECK(cp, sigfieldlen);
198         sigstart = cp;
199         cp += sigfieldlen;
200
201         /* Skip id and read error. */
202         BOUNDS_CHECK(cp, 2*INT16SZ);
203         cp += INT16SZ;
204         GETSHORT(error, cp);
205
206         /* Parse the other data. */
207         BOUNDS_CHECK(cp, INT16SZ);
208         GETSHORT(otherfieldlen, cp);
209         BOUNDS_CHECK(cp, otherfieldlen);
210         otherstart = cp;
211         cp += otherfieldlen;
212
213         if (cp != eom)
214                 return (NS_TSIG_ERROR_FORMERR);
215
216         /* Verify that the key used is OK. */
217         if (key != NULL) {
218                 if (key->dk_alg != KEY_HMAC_MD5)
219                         return (-ns_r_badkey);
220                 if (error != ns_r_badsig && error != ns_r_badkey) {
221                         if (ns_samename(key->dk_key_name, name) != 1)
222                                 return (-ns_r_badkey);
223                 }
224         }
225
226         hp->arcount = htons(ntohs(hp->arcount) - 1);
227
228         /*
229          * Do the verification.
230          */
231
232         if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
233                 void *ctx;
234                 u_char buf[MAXDNAME];
235                 u_char buf2[MAXDNAME];
236
237                 /* Digest the query signature, if this is a response. */
238                 dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
239                 if (querysiglen > 0 && querysig != NULL) {
240                         u_int16_t len_n = htons(querysiglen);
241                         dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
242                                         (u_char *)&len_n, INT16SZ, NULL, 0);
243                         dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
244                                         querysig, querysiglen, NULL, 0);
245                 }
246                 
247                 /* Digest the message. */
248                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg,
249                                 NULL, 0);
250
251                 /* Digest the key name. */
252                 n = ns_name_pton(name, buf2, sizeof(buf2));
253                 if (n < 0)
254                         return (-1);
255                 n = ns_name_ntol(buf2, buf, sizeof(buf));
256                 if (n < 0)
257                         return (-1);
258                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
259
260                 /* Digest the class and TTL. */
261                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
262                                 recstart + dn_skipname(recstart, eom) + INT16SZ,
263                                 INT16SZ + INT32SZ, NULL, 0);
264
265                 /* Digest the algorithm. */
266                 n = ns_name_pton(alg, buf2, sizeof(buf2));
267                 if (n < 0)
268                         return (-1);
269                 n = ns_name_ntol(buf2, buf, sizeof(buf));
270                 if (n < 0)
271                         return (-1);
272                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
273
274                 /* Digest the time signed and fudge. */
275                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
276                                 rdatastart + dn_skipname(rdatastart, eom),
277                                 INT16SZ + INT32SZ + INT16SZ, NULL, 0);
278
279                 /* Digest the error and other data. */
280                 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
281                                 otherstart - INT16SZ - INT16SZ,
282                                 otherfieldlen + INT16SZ + INT16SZ, NULL, 0);
283
284                 n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
285                                     sigstart, sigfieldlen);
286
287                 if (n < 0)
288                         return (-ns_r_badsig);
289
290                 if (sig != NULL && siglen != NULL) {
291                         if (*siglen < sigfieldlen)
292                                 return (NS_TSIG_ERROR_NO_SPACE);
293                         memcpy(sig, sigstart, sigfieldlen);
294                         *siglen = sigfieldlen;
295                 }
296         } else {
297                 if (sigfieldlen > 0)
298                         return (NS_TSIG_ERROR_FORMERR);
299                 if (sig != NULL && siglen != NULL)
300                         *siglen = 0;
301         }
302
303         /* Reset the counter, since we still need to check for badtime. */
304         hp->arcount = htons(ntohs(hp->arcount) + 1);
305
306         /* Verify the time. */
307         if (abs((*timesigned) - time(NULL)) > fudge)
308                 return (-ns_r_badtime);
309
310         if (nostrip == 0) {
311                 *msglen = recstart - msg;
312                 hp->arcount = htons(ntohs(hp->arcount) - 1);
313         }
314
315         if (error != NOERROR)
316                 return (error);
317
318         return (0);
319 }
320
321 int
322 ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen,
323                    ns_tcp_tsig_state *state)
324 {
325         dst_init();
326         if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
327                 return (-1);
328         state->counter = -1;
329         state->key = k;
330         if (state->key->dk_alg != KEY_HMAC_MD5)
331                 return (-ns_r_badkey);
332         if (querysiglen > (int)sizeof(state->sig))
333                 return (-1);
334         memcpy(state->sig, querysig, querysiglen);
335         state->siglen = querysiglen;
336         return (0);
337 }
338
339 int
340 ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state,
341               int required)
342 {
343         HEADER *hp = (HEADER *)msg;
344         u_char *recstart, *sigstart;
345         unsigned int sigfieldlen, otherfieldlen;
346         u_char *cp, *eom, *cp2;
347         char name[MAXDNAME], alg[MAXDNAME];
348         u_char buf[MAXDNAME];
349         int n, type, length, fudge, error;
350         time_t timesigned;
351
352         if (msg == NULL || msglen == NULL || state == NULL)
353                 return (-1);
354
355         eom = msg + *msglen;
356
357         state->counter++;
358         if (state->counter == 0)
359                 return (ns_verify(msg, msglen, state->key,
360                                   state->sig, state->siglen,
361                                   state->sig, &state->siglen, &timesigned, 0));
362
363         if (state->siglen > 0) {
364                 u_int16_t siglen_n = htons(state->siglen);
365
366                 dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
367                                 NULL, 0, NULL, 0);
368                 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
369                                 (u_char *)&siglen_n, INT16SZ, NULL, 0);
370                 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
371                                 state->sig, state->siglen, NULL, 0);
372                 state->siglen = 0;
373         }
374
375         cp = recstart = ns_find_tsig(msg, eom);
376
377         if (recstart == NULL) {
378                 if (required)
379                         return (NS_TSIG_ERROR_NO_TSIG);
380                 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
381                                 msg, *msglen, NULL, 0);
382                 return (0);
383         }
384
385         hp->arcount = htons(ntohs(hp->arcount) - 1);
386         dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
387                         msg, recstart - msg, NULL, 0);
388         
389         /* Read the key name. */
390         n = dn_expand(msg, eom, cp, name, MAXDNAME);
391         if (n < 0)
392                 return (NS_TSIG_ERROR_FORMERR);
393         cp += n;
394
395         /* Read the type. */
396         BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
397         GETSHORT(type, cp);
398         if (type != ns_t_tsig)
399                 return (NS_TSIG_ERROR_NO_TSIG);
400
401         /* Skip the class and TTL, save the length. */
402         cp += INT16SZ + INT32SZ;
403         GETSHORT(length, cp);
404         if (eom - cp != length)
405                 return (NS_TSIG_ERROR_FORMERR);
406
407         /* Read the algorithm name. */
408         n = dn_expand(msg, eom, cp, alg, MAXDNAME);
409         if (n < 0)
410                 return (NS_TSIG_ERROR_FORMERR);
411         if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
412                 return (-ns_r_badkey);
413         cp += n;
414
415         /* Verify that the key used is OK. */
416         if ((ns_samename(state->key->dk_key_name, name) != 1 ||
417              state->key->dk_alg != KEY_HMAC_MD5))
418                 return (-ns_r_badkey);
419
420         /* Read the time signed and fudge. */
421         BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
422         cp += INT16SZ;
423         GETLONG(timesigned, cp);
424         GETSHORT(fudge, cp);
425
426         /* Read the signature. */
427         BOUNDS_CHECK(cp, INT16SZ);
428         GETSHORT(sigfieldlen, cp);
429         BOUNDS_CHECK(cp, sigfieldlen);
430         sigstart = cp;
431         cp += sigfieldlen;
432
433         /* Skip id and read error. */
434         BOUNDS_CHECK(cp, 2*INT16SZ);
435         cp += INT16SZ;
436         GETSHORT(error, cp);
437
438         /* Parse the other data. */
439         BOUNDS_CHECK(cp, INT16SZ);
440         GETSHORT(otherfieldlen, cp);
441         BOUNDS_CHECK(cp, otherfieldlen);
442         cp += otherfieldlen;
443
444         if (cp != eom)
445                 return (NS_TSIG_ERROR_FORMERR);
446
447         /*
448          * Do the verification.
449          */
450
451         /* Digest the time signed and fudge. */
452         cp2 = buf;
453         PUTSHORT(0, cp2);       /* Top 16 bits of time. */
454         PUTLONG(timesigned, cp2);
455         PUTSHORT(NS_TSIG_FUDGE, cp2);
456
457         dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
458                         buf, cp2 - buf, NULL, 0);
459
460         n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
461                             sigstart, sigfieldlen);
462         if (n < 0)
463                 return (-ns_r_badsig);
464
465         if (sigfieldlen > sizeof(state->sig))
466                 return (NS_TSIG_ERROR_NO_SPACE);
467
468         memcpy(state->sig, sigstart, sigfieldlen);
469         state->siglen = sigfieldlen;
470
471         /* Verify the time. */
472         if (abs(timesigned - time(NULL)) > fudge)
473                 return (-ns_r_badtime);
474
475         *msglen = recstart - msg;
476
477         if (error != NOERROR)
478                 return (error);
479
480         return (0);
481 }