]> git.saurik.com Git - apple/libresolv.git/blob - ns_verify.c
libresolv-19.tar.gz
[apple/libresolv.git] / ns_verify.c
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
20 static 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
66 u_char *
67 ns_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 */
141 int
142 ns_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
329 int
330 ns_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
347 int
348 ns_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 }