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