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, ×igned, 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