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