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