Annotation of embedaddon/dhcp/minires/ns_verify.c, revision 1.1.1.1.2.1
1.1 misho 1: /*
2: * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
3: * Copyright (c) 1999-2003 by Internet Software Consortium
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: * Internet Systems Consortium, Inc.
18: * 950 Charter Street
19: * Redwood City, CA 94063
20: * <info@isc.org>
21: * https://www.isc.org/
22: */
23:
24: #ifndef lint
1.1.1.1.2.1! misho 25: static const char rcsid[] = "$Id: ns_verify.c,v 1.1.1.1 2012/10/09 09:06:54 misho Exp $";
1.1 misho 26: #endif
27:
28: /* Import. */
29:
30: #include <sys/types.h>
31: #include <sys/param.h>
32:
33: #include <netinet/in.h>
34: #include <arpa/inet.h>
35: #include <sys/socket.h>
36:
37: #include <errno.h>
38: #include <netdb.h>
39: #include <stdio.h>
40: #include <stdlib.h>
41: #include <string.h>
42: #include <unistd.h>
43: #include <time.h>
44:
45: #define time(x) trace_mr_time (x)
46:
47: #include "minires/minires.h"
48: #include "arpa/nameser.h"
49: #include <isc-dhcp/dst.h>
50:
51: time_t trace_mr_time (time_t *);
52:
53: /* Private. */
54:
55: #define BOUNDS_CHECK(ptr, count) \
56: do { \
57: if ((ptr) + (count) > eom) { \
58: return (NS_TSIG_ERROR_FORMERR); \
59: } \
60: } while (0)
61:
62: /* Public. */
63:
64: u_char *
65: ns_find_tsig(u_char *msg, u_char *eom) {
66: HEADER *hp = (HEADER *)msg;
67: int n, type;
68: u_char *cp = msg, *start;
69: isc_result_t status;
70:
71: if (msg == NULL || eom == NULL || msg > eom)
72: return (NULL);
73:
74: if (cp + HFIXEDSZ >= eom)
75: return (NULL);
76:
77: if (hp->arcount == 0)
78: return (NULL);
79:
80: cp += HFIXEDSZ;
81:
82: status = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount), &n);
83: if (status != ISC_R_SUCCESS)
84: return (NULL);
85: cp += n;
86:
87: status = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount), &n);
88: if (status != ISC_R_SUCCESS)
89: return (NULL);
90: cp += n;
91:
92: status = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount), &n);
93: if (status != ISC_R_SUCCESS)
94: return (NULL);
95: cp += n;
96:
97: status = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1, &n);
98: if (status != ISC_R_SUCCESS)
99: return (NULL);
100: cp += n;
101:
102: start = cp;
103: n = dn_skipname(cp, eom);
104: if (n < 0)
105: return (NULL);
106: cp += n;
107: if (cp + INT16SZ >= eom)
108: return (NULL);
109:
110: GETSHORT(type, cp);
111: if (type != ns_t_tsig)
112: return (NULL);
113: return (start);
114: }
115:
116: /* ns_verify
117: * Parameters:
118: * statp res stuff
119: * msg received message
120: * msglen length of message
121: * key tsig key used for verifying.
122: * querysig (response), the signature in the query
123: * querysiglen (response), the length of the signature in the query
124: * sig (query), a buffer to hold the signature
125: * siglen (query), input - length of signature buffer
126: * output - length of signature
127: *
128: * Errors:
129: * - bad input (-1)
130: * - invalid dns message (NS_TSIG_ERROR_FORMERR)
131: * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
132: * - key doesn't match (-ns_r_badkey)
133: * - TSIG verification fails with BADKEY (-ns_r_badkey)
134: * - TSIG verification fails with BADSIG (-ns_r_badsig)
135: * - TSIG verification fails with BADTIME (-ns_r_badtime)
136: * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
137: * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
138: * - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
139: */
140: isc_result_t
141: ns_verify(u_char *msg, unsigned *msglen, void *k,
142: const u_char *querysig, unsigned querysiglen,
143: u_char *sig, unsigned *siglen, time_t *timesigned, int nostrip)
144: {
145: HEADER *hp = (HEADER *)msg;
146: DST_KEY *key = (DST_KEY *)k;
147: u_char *cp = msg, *eom;
148: char name[MAXDNAME], alg[MAXDNAME];
149: u_char *recstart, *rdatastart;
150: u_char *sigstart, *otherstart;
151: unsigned n;
152: int error;
153: u_int16_t type, length;
154: u_int16_t fudge, sigfieldlen, id, otherfieldlen;
155:
156: dst_init();
1.1.1.1.2.1! misho 157: if (msg == NULL || msglen == NULL)
1.1 misho 158: return ISC_R_INVALIDARG;
159:
160: eom = msg + *msglen;
161:
162: recstart = ns_find_tsig(msg, eom);
163: if (recstart == NULL)
164: return ISC_R_NO_TSIG;
165:
166: cp = recstart;
167:
168: /* Read the key name. */
169: n = dn_expand(msg, eom, cp, name, MAXDNAME);
1.1.1.1.2.1! misho 170: if (n)
1.1 misho 171: return ISC_R_FORMERR;
172: cp += n;
173:
174: /* Read the type. */
175: BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
176: GETSHORT(type, cp);
177: if (type != ns_t_tsig)
178: return ISC_R_NO_TSIG;
179:
180: /* Skip the class and TTL, save the length. */
181: cp += INT16SZ + INT32SZ;
182: GETSHORT(length, cp);
183: if (eom - cp != length)
184: return ISC_R_FORMERR;
185:
186: /* Read the algorithm name. */
187: rdatastart = cp;
188: n = dn_expand(msg, eom, cp, alg, MAXDNAME);
1.1.1.1.2.1! misho 189: if (n)
1.1 misho 190: return ISC_R_FORMERR;
191: if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
192: return ISC_R_INVALIDKEY;
193: cp += n;
194:
195: /* Read the time signed and fudge. */
196: BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
197: cp += INT16SZ;
198: GETLONG((*timesigned), cp);
199: GETSHORT(fudge, cp);
200:
201: /* Read the signature. */
202: BOUNDS_CHECK(cp, INT16SZ);
203: GETSHORT(sigfieldlen, cp);
204: BOUNDS_CHECK(cp, sigfieldlen);
205: sigstart = cp;
206: cp += sigfieldlen;
207:
208: /* Read the original id and error. */
209: BOUNDS_CHECK(cp, 2*INT16SZ);
210: GETSHORT(id, cp);
211: GETSHORT(error, cp);
212:
1.1.1.1 misho 213: /* Let's silence set-but-unused compilation warning */
214: IGNORE_UNUSED(id);
215:
1.1 misho 216: /* Parse the other data. */
217: BOUNDS_CHECK(cp, INT16SZ);
218: GETSHORT(otherfieldlen, cp);
219: BOUNDS_CHECK(cp, otherfieldlen);
220: otherstart = cp;
221: cp += otherfieldlen;
222:
223: if (cp != eom)
224: return ISC_R_FORMERR;
225:
226: /* Verify that the key used is OK. */
227: if (key != NULL) {
228: if (key->dk_alg != KEY_HMAC_MD5)
229: return ISC_R_INVALIDKEY;
230: if (error != ns_r_badsig && error != ns_r_badkey) {
231: if (ns_samename(key->dk_key_name, name) != 1)
232: return ISC_R_INVALIDKEY;
233: }
234: }
235:
236: hp->arcount = htons(ntohs(hp->arcount) - 1);
237:
238: /*
239: * Do the verification.
240: */
241:
242: if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
243: void *ctx;
244: u_char buf[MAXDNAME];
245:
246: /* Digest the query signature, if this is a response. */
247: dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
248: if (querysiglen > 0 && querysig != NULL) {
249: u_int16_t len_n = htons(querysiglen);
250: dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
251: (u_char *)&len_n, INT16SZ, NULL, 0);
252: dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
253: querysig, querysiglen, NULL, 0);
254: }
255:
256: /* Digest the message. */
257: dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg,
258: (unsigned)(recstart - msg), NULL, 0);
259:
260: /* Digest the key name. */
261: n = ns_name_ntol(recstart, buf, sizeof(buf));
262: dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
263:
264: /* Digest the class and TTL. */
265: dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
266: recstart + dn_skipname(recstart, eom) + INT16SZ,
267: INT16SZ + INT32SZ, NULL, 0);
268:
269: /* Digest the algorithm. */
270: n = ns_name_ntol(rdatastart, buf, sizeof(buf));
271: dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
272:
273: /* Digest the time signed and fudge. */
274: dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
275: rdatastart + dn_skipname(rdatastart, eom),
276: INT16SZ + INT32SZ + INT16SZ, NULL, 0);
277:
278: /* Digest the error and other data. */
279: dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
280: otherstart - INT16SZ - INT16SZ,
281: (unsigned)otherfieldlen + INT16SZ + INT16SZ,
282: NULL, 0);
283:
284: n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
285: sigstart, sigfieldlen);
286:
1.1.1.1.2.1! misho 287: if (n)
1.1 misho 288: return ISC_R_BADSIG;
289:
290: if (sig != NULL && siglen != NULL) {
291: if (*siglen < sigfieldlen)
292: return ISC_R_NOSPACE;
293: memcpy(sig, sigstart, sigfieldlen);
294: *siglen = sigfieldlen;
295: }
296: } else {
297: if (sigfieldlen > 0)
298: return ISC_R_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 ISC_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 ns_rcode_to_isc (error);
317:
318: return ISC_R_SUCCESS;
319: }
320:
321: #if 0
322: isc_result_t
323: ns_verify_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
324: ns_tcp_tsig_state *state)
325: {
326: dst_init();
327: if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
328: return ISC_R_INVALIDARG;
329: state->counter = -1;
330: state->key = k;
331: if (state->key->dk_alg != KEY_HMAC_MD5)
332: return ISC_R_BADKEY;
333: if (querysiglen > sizeof(state->sig))
334: return ISC_R_NOSPACE;
335: memcpy(state->sig, querysig, querysiglen);
336: state->siglen = querysiglen;
337: return ISC_R_SUCCESS;
338: }
339:
340: isc_result_t
341: ns_verify_tcp(u_char *msg, unsigned *msglen, ns_tcp_tsig_state *state,
342: int required)
343: {
344: HEADER *hp = (HEADER *)msg;
345: u_char *recstart, *rdatastart, *sigstart;
346: unsigned sigfieldlen, otherfieldlen;
347: u_char *cp, *eom = msg + *msglen, *cp2;
348: char name[MAXDNAME], alg[MAXDNAME];
349: u_char buf[MAXDNAME];
350: int n, type, length, fudge, id, error;
351: time_t timesigned;
352:
353: if (msg == NULL || msglen == NULL || state == NULL)
354: return ISC_R_INVALIDARG;
355:
356: state->counter++;
357: if (state->counter == 0)
358: return (ns_verify(msg, msglen, state->key,
359: state->sig, state->siglen,
360: state->sig, &state->siglen, ×igned, 0));
361:
362: if (state->siglen > 0) {
363: u_int16_t siglen_n = htons(state->siglen);
364:
365: dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
366: NULL, 0, NULL, 0);
367: dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
368: (u_char *)&siglen_n, INT16SZ, NULL, 0);
369: dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
370: state->sig, state->siglen, NULL, 0);
371: state->siglen = 0;
372: }
373:
374: cp = recstart = ns_find_tsig(msg, eom);
375:
376: if (recstart == NULL) {
377: if (required)
378: return ISC_R_NO_TSIG;
379: dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
380: msg, *msglen, NULL, 0);
381: return ISC_R_SUCCESS;
382: }
383:
384: hp->arcount = htons(ntohs(hp->arcount) - 1);
385: dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
386: msg, (unsigned)(recstart - msg), NULL, 0);
387:
388: /* Read the key name. */
389: n = dn_expand(msg, eom, cp, name, MAXDNAME);
390: if (n < 0)
391: return ISC_R_FORMERR;
392: cp += n;
393:
394: /* Read the type. */
395: BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
396: GETSHORT(type, cp);
397: if (type != ns_t_tsig)
398: return ISC_R_NO_TSIG;
399:
400: /* Skip the class and TTL, save the length. */
401: cp += INT16SZ + INT32SZ;
402: GETSHORT(length, cp);
403: if (eom - cp != length)
404: return ISC_R_FORMERR;
405:
406: /* Read the algorithm name. */
407: rdatastart = cp;
408: n = dn_expand(msg, eom, cp, alg, MAXDNAME);
409: if (n < 0)
410: return ISC_R_FORMERR;
411: if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
412: return ISC_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 ISC_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: /* Read the original id and error. */
434: BOUNDS_CHECK(cp, 2*INT16SZ);
435: GETSHORT(id, cp);
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 ISC_R_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, (unsigned)(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 ISC_R_BADSIG;
464:
465: if (sigfieldlen > sizeof(state->sig))
466: return ISC_R_BADSIG;
467:
468: if (sigfieldlen > sizeof(state->sig))
469: return ISC_R_NOSPACE;
470:
471: memcpy(state->sig, sigstart, sigfieldlen);
472: state->siglen = sigfieldlen;
473:
474: /* Verify the time. */
475: if (abs(timesigned - time(NULL)) > fudge)
476: return ISC_R_BADTIME;
477:
478: *msglen = recstart - msg;
479:
480: if (error != NOERROR)
481: return ns_rcode_to_isc (error);
482:
483: return ISC_R_SUCCESS;
484: }
485: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>