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