Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / minires / ns_verify.c
blob2212b1e20f9c21f317f3774917d3a103ecb790d3
1 /*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1999-2003 by Internet Software Consortium
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.
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.
17 * Internet Systems Consortium, Inc.
18 * 950 Charter Street
19 * Redwood City, CA 94063
20 * <info@isc.org>
21 * http://www.isc.org/
24 #ifndef lint
25 static const char rcsid[] = "$Id: ns_verify.c,v 1.3 2005/08/11 17:13:26 drochner Exp $";
26 #endif
28 #define time(x) trace_mr_time (x)
30 /* Import. */
32 #include <sys/types.h>
33 #include <sys/param.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <sys/socket.h>
39 #include <errno.h>
40 #include <netdb.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <time.h>
47 #include "minires/minires.h"
48 #include "arpa/nameser.h"
49 #include <isc-dhcp/dst.h>
51 time_t trace_mr_time (time_t *);
53 /* Private. */
55 #define BOUNDS_CHECK(ptr, count) \
56 do { \
57 if ((ptr) + (count) > eom) { \
58 return (NS_TSIG_ERROR_FORMERR); \
59 } \
60 } while (0)
62 /* Public. */
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;
71 if (msg == NULL || eom == NULL || msg > eom)
72 return (NULL);
74 if (cp + HFIXEDSZ >= eom)
75 return (NULL);
77 if (hp->arcount == 0)
78 return (NULL);
80 cp += HFIXEDSZ;
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;
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;
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;
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;
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);
110 GETSHORT(type, cp);
111 if (type != ns_t_tsig)
112 return (NULL);
113 return (start);
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
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)
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)
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;
156 dst_init();
157 if (msg == NULL || msglen == NULL || *msglen < 0)
158 return ISC_R_INVALIDARG;
160 eom = msg + *msglen;
162 recstart = ns_find_tsig(msg, eom);
163 if (recstart == NULL)
164 return ISC_R_NO_TSIG;
166 cp = recstart;
168 /* Read the key name. */
169 n = dn_expand(msg, eom, cp, name, MAXDNAME);
170 if (n < 0)
171 return ISC_R_FORMERR;
172 cp += n;
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;
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;
186 /* Read the algorithm name. */
187 rdatastart = cp;
188 n = dn_expand(msg, eom, cp, alg, MAXDNAME);
189 if (n < 0)
190 return ISC_R_FORMERR;
191 if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
192 return ISC_R_INVALIDKEY;
193 cp += n;
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);
201 /* Read the signature. */
202 BOUNDS_CHECK(cp, INT16SZ);
203 GETSHORT(sigfieldlen, cp);
204 BOUNDS_CHECK(cp, sigfieldlen);
205 sigstart = cp;
206 cp += sigfieldlen;
208 /* Read the original id and error. */
209 BOUNDS_CHECK(cp, 2*INT16SZ);
210 GETSHORT(id, cp);
211 GETSHORT(error, cp);
213 /* Parse the other data. */
214 BOUNDS_CHECK(cp, INT16SZ);
215 GETSHORT(otherfieldlen, cp);
216 BOUNDS_CHECK(cp, otherfieldlen);
217 otherstart = cp;
218 cp += otherfieldlen;
220 if (cp != eom)
221 return ISC_R_FORMERR;
223 /* Verify that the key used is OK. */
224 if (key != NULL) {
225 if (key->dk_alg != KEY_HMAC_MD5)
226 return ISC_R_INVALIDKEY;
227 if (error != ns_r_badsig && error != ns_r_badkey) {
228 if (ns_samename(key->dk_key_name, name) != 1)
229 return ISC_R_INVALIDKEY;
233 hp->arcount = htons(ntohs(hp->arcount) - 1);
236 * Do the verification.
239 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
240 void *ctx;
241 u_char buf[MAXDNAME];
243 /* Digest the query signature, if this is a response. */
244 dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
245 if (querysiglen > 0 && querysig != NULL) {
246 u_int16_t len_n = htons(querysiglen);
247 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
248 (u_char *)&len_n, INT16SZ, NULL, 0);
249 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
250 querysig, querysiglen, NULL, 0);
253 /* Digest the message. */
254 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg,
255 (unsigned)(recstart - msg), NULL, 0);
257 /* Digest the key name. */
258 n = ns_name_ntol(recstart, buf, sizeof(buf));
259 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
261 /* Digest the class and TTL. */
262 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
263 recstart + dn_skipname(recstart, eom) + INT16SZ,
264 INT16SZ + INT32SZ, NULL, 0);
266 /* Digest the algorithm. */
267 n = ns_name_ntol(rdatastart, buf, sizeof(buf));
268 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
270 /* Digest the time signed and fudge. */
271 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
272 rdatastart + dn_skipname(rdatastart, eom),
273 INT16SZ + INT32SZ + INT16SZ, NULL, 0);
275 /* Digest the error and other data. */
276 dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
277 otherstart - INT16SZ - INT16SZ,
278 (unsigned)otherfieldlen + INT16SZ + INT16SZ,
279 NULL, 0);
281 n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
282 sigstart, sigfieldlen);
284 if (n < 0)
285 return ISC_R_BADSIG;
287 if (sig != NULL && siglen != NULL) {
288 if (*siglen < sigfieldlen)
289 return ISC_R_NOSPACE;
290 memcpy(sig, sigstart, sigfieldlen);
291 *siglen = sigfieldlen;
293 } else {
294 if (sigfieldlen > 0)
295 return ISC_R_FORMERR;
296 if (sig != NULL && siglen != NULL)
297 *siglen = 0;
300 /* Reset the counter, since we still need to check for badtime. */
301 hp->arcount = htons(ntohs(hp->arcount) + 1);
303 /* Verify the time. */
304 if (abs((*timesigned) - time(NULL)) > fudge)
305 return ISC_R_BADTIME;
307 if (nostrip == 0) {
308 *msglen = recstart - msg;
309 hp->arcount = htons(ntohs(hp->arcount) - 1);
312 if (error != NOERROR)
313 return ns_rcode_to_isc (error);
315 return ISC_R_SUCCESS;
318 #if 0
319 isc_result_t
320 ns_verify_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
321 ns_tcp_tsig_state *state)
323 dst_init();
324 if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
325 return ISC_R_INVALIDARG;
326 state->counter = -1;
327 state->key = k;
328 if (state->key->dk_alg != KEY_HMAC_MD5)
329 return ISC_R_BADKEY;
330 if (querysiglen > sizeof(state->sig))
331 return ISC_R_NOSPACE;
332 memcpy(state->sig, querysig, querysiglen);
333 state->siglen = querysiglen;
334 return ISC_R_SUCCESS;
337 isc_result_t
338 ns_verify_tcp(u_char *msg, unsigned *msglen, ns_tcp_tsig_state *state,
339 int required)
341 HEADER *hp = (HEADER *)msg;
342 u_char *recstart, *rdatastart, *sigstart;
343 unsigned sigfieldlen, otherfieldlen;
344 u_char *cp, *eom = msg + *msglen, *cp2;
345 char name[MAXDNAME], alg[MAXDNAME];
346 u_char buf[MAXDNAME];
347 int n, type, length, fudge, id, error;
348 time_t timesigned;
350 if (msg == NULL || msglen == NULL || state == NULL)
351 return ISC_R_INVALIDARG;
353 state->counter++;
354 if (state->counter == 0)
355 return (ns_verify(msg, msglen, state->key,
356 state->sig, state->siglen,
357 state->sig, &state->siglen, &timesigned, 0));
359 if (state->siglen > 0) {
360 u_int16_t siglen_n = htons(state->siglen);
362 dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
363 NULL, 0, NULL, 0);
364 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
365 (u_char *)&siglen_n, INT16SZ, NULL, 0);
366 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
367 state->sig, state->siglen, NULL, 0);
368 state->siglen = 0;
371 cp = recstart = ns_find_tsig(msg, eom);
373 if (recstart == NULL) {
374 if (required)
375 return ISC_R_NO_TSIG;
376 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
377 msg, *msglen, NULL, 0);
378 return ISC_R_SUCCESS;
381 hp->arcount = htons(ntohs(hp->arcount) - 1);
382 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
383 msg, (unsigned)(recstart - msg), NULL, 0);
385 /* Read the key name. */
386 n = dn_expand(msg, eom, cp, name, MAXDNAME);
387 if (n < 0)
388 return ISC_R_FORMERR;
389 cp += n;
391 /* Read the type. */
392 BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
393 GETSHORT(type, cp);
394 if (type != ns_t_tsig)
395 return ISC_R_NO_TSIG;
397 /* Skip the class and TTL, save the length. */
398 cp += INT16SZ + INT32SZ;
399 GETSHORT(length, cp);
400 if (eom - cp != length)
401 return ISC_R_FORMERR;
403 /* Read the algorithm name. */
404 rdatastart = cp;
405 n = dn_expand(msg, eom, cp, alg, MAXDNAME);
406 if (n < 0)
407 return ISC_R_FORMERR;
408 if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
409 return ISC_R_BADKEY;
410 cp += n;
412 /* Verify that the key used is OK. */
413 if ((ns_samename(state->key->dk_key_name, name) != 1 ||
414 state->key->dk_alg != KEY_HMAC_MD5))
415 return ISC_R_BADKEY;
417 /* Read the time signed and fudge. */
418 BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
419 cp += INT16SZ;
420 GETLONG(timesigned, cp);
421 GETSHORT(fudge, cp);
423 /* Read the signature. */
424 BOUNDS_CHECK(cp, INT16SZ);
425 GETSHORT(sigfieldlen, cp);
426 BOUNDS_CHECK(cp, sigfieldlen);
427 sigstart = cp;
428 cp += sigfieldlen;
430 /* Read the original id and error. */
431 BOUNDS_CHECK(cp, 2*INT16SZ);
432 GETSHORT(id, cp);
433 GETSHORT(error, cp);
435 /* Parse the other data. */
436 BOUNDS_CHECK(cp, INT16SZ);
437 GETSHORT(otherfieldlen, cp);
438 BOUNDS_CHECK(cp, otherfieldlen);
439 cp += otherfieldlen;
441 if (cp != eom)
442 return ISC_R_FORMERR;
445 * Do the verification.
448 /* Digest the time signed and fudge. */
449 cp2 = buf;
450 PUTSHORT(0, cp2); /* Top 16 bits of time. */
451 PUTLONG(timesigned, cp2);
452 PUTSHORT(NS_TSIG_FUDGE, cp2);
454 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
455 buf, (unsigned)(cp2 - buf), NULL, 0);
457 n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
458 sigstart, sigfieldlen);
459 if (n < 0)
460 return ISC_R_BADSIG;
462 if (sigfieldlen > sizeof(state->sig))
463 return ISC_R_BADSIG;
465 if (sigfieldlen > sizeof(state->sig))
466 return ISC_R_NOSPACE;
468 memcpy(state->sig, sigstart, sigfieldlen);
469 state->siglen = sigfieldlen;
471 /* Verify the time. */
472 if (abs(timesigned - time(NULL)) > fudge)
473 return ISC_R_BADTIME;
475 *msglen = recstart - msg;
477 if (error != NOERROR)
478 return ns_rcode_to_isc (error);
480 return ISC_R_SUCCESS;
482 #endif