]>
git.saurik.com Git - apple/libresolv.git/blob - ns_verify.c
2 * Copyright (c) 1999 by Internet Software Consortium, Inc.
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.
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
20 static const char rcsid
[] = "$Id: ns_verify.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
27 #include "port_before.h"
28 #include "fd_setsize.h"
31 #include <sys/types.h>
32 #include <sys/param.h>
34 #include <netinet/in.h>
35 #include <arpa/nameser.h>
36 #include <arpa/inet.h>
49 #include "port_after.h"
51 #include "dst_internal.h"
52 #include "res_private.h"
57 #define BOUNDS_CHECK(ptr, count) \
59 if ((ptr) + (count) > eom) { \
60 return (NS_TSIG_ERROR_FORMERR); \
67 ns_find_tsig(u_char
*msg
, u_char
*eom
) {
68 HEADER
*hp
= (HEADER
*)msg
;
70 u_char
*cp
= msg
, *start
;
72 if (msg
== NULL
|| eom
== NULL
|| msg
> eom
)
75 if (cp
+ NS_HFIXEDSZ
>= eom
)
83 n
= ns_skiprr(cp
, eom
, ns_s_qd
, ntohs(hp
->qdcount
));
88 n
= ns_skiprr(cp
, eom
, ns_s_an
, ntohs(hp
->ancount
));
93 n
= ns_skiprr(cp
, eom
, ns_s_ns
, ntohs(hp
->nscount
));
98 n
= ns_skiprr(cp
, eom
, ns_s_ar
, ntohs(hp
->arcount
) - 1);
104 n
= dn_skipname(cp
, eom
);
108 if (cp
+ NS_INT16SZ
>= eom
)
112 if (type
!= ns_t_tsig
)
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
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)
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
)
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
;
154 u_int16_t type
, length
;
155 u_int16_t fudge
, sigfieldlen
, id
, otherfieldlen
;
158 if (msg
== NULL
|| msglen
== NULL
|| *msglen
< 0)
163 recstart
= ns_find_tsig(msg
, eom
);
164 if (recstart
== NULL
)
165 return (NS_TSIG_ERROR_NO_TSIG
);
169 /* Read the key name. */
170 n
= dn_expand(msg
, eom
, cp
, name
, NS_MAXDNAME
);
172 return (NS_TSIG_ERROR_FORMERR
);
176 BOUNDS_CHECK(cp
, 2*NS_INT16SZ
+ NS_INT32SZ
+ NS_INT16SZ
);
178 if (type
!= ns_t_tsig
)
179 return (NS_TSIG_ERROR_NO_TSIG
);
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
);
187 /* Read the algorithm name. */
189 n
= dn_expand(msg
, eom
, cp
, alg
, NS_MAXDNAME
);
191 return (NS_TSIG_ERROR_FORMERR
);
192 if (ns_samename(alg
, NS_TSIG_ALG_HMAC_MD5
) != 1)
193 return (-ns_r_badkey
);
196 /* Read the time signed and fudge. */
197 BOUNDS_CHECK(cp
, NS_INT16SZ
+ NS_INT32SZ
+ NS_INT16SZ
);
199 NS_GET32((*timesigned
), cp
);
202 /* Read the signature. */
203 BOUNDS_CHECK(cp
, NS_INT16SZ
);
204 NS_GET16(sigfieldlen
, cp
);
205 BOUNDS_CHECK(cp
, sigfieldlen
);
209 /* Read the original id and error. */
210 BOUNDS_CHECK(cp
, 2*NS_INT16SZ
);
214 /* Parse the other data. */
215 BOUNDS_CHECK(cp
, NS_INT16SZ
);
216 NS_GET16(otherfieldlen
, cp
);
217 BOUNDS_CHECK(cp
, otherfieldlen
);
222 return (NS_TSIG_ERROR_FORMERR
);
224 /* Verify that the key used is OK. */
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
);
234 hp
->arcount
= htons(ntohs(hp
->arcount
) - 1);
237 * Do the verification.
240 if (key
!= NULL
&& error
!= ns_r_badsig
&& error
!= ns_r_badkey
) {
242 u_char buf
[NS_MAXDNAME
];
243 u_char buf2
[NS_MAXDNAME
];
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);
255 /* Digest the message. */
256 dst_verify_data(SIG_MODE_UPDATE
, key
, &ctx
, msg
, recstart
- msg
,
259 /* Digest the key name. */
260 n
= ns_name_pton(name
, buf2
, sizeof(buf2
));
263 n
= ns_name_ntol(buf2
, buf
, sizeof(buf
));
266 dst_verify_data(SIG_MODE_UPDATE
, key
, &ctx
, buf
, n
, NULL
, 0);
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);
273 /* Digest the algorithm. */
274 n
= ns_name_pton(alg
, buf2
, sizeof(buf2
));
277 n
= ns_name_ntol(buf2
, buf
, sizeof(buf
));
280 dst_verify_data(SIG_MODE_UPDATE
, key
, &ctx
, buf
, n
, NULL
, 0);
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);
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);
292 n
= dst_verify_data(SIG_MODE_FINAL
, key
, &ctx
, NULL
, 0,
293 sigstart
, sigfieldlen
);
296 return (-ns_r_badsig
);
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
;
306 return (NS_TSIG_ERROR_FORMERR
);
307 if (sig
!= NULL
&& siglen
!= NULL
)
311 /* Reset the counter, since we still need to check for badtime. */
312 hp
->arcount
= htons(ntohs(hp
->arcount
) + 1);
314 /* Verify the time. */
315 if (abs((*timesigned
) - time(NULL
)) > fudge
)
316 return (-ns_r_badtime
);
319 *msglen
= recstart
- msg
;
320 hp
->arcount
= htons(ntohs(hp
->arcount
) - 1);
323 if (error
!= ns_r_noerror
)
330 ns_verify_tcp_init(void *k
, const u_char
*querysig
, int querysiglen
,
331 ns_tcp_tsig_state
*state
)
334 if (state
== NULL
|| k
== NULL
|| querysig
== NULL
|| querysiglen
< 0)
338 if (state
->key
->dk_alg
!= KEY_HMAC_MD5
)
339 return (-ns_r_badkey
);
340 if (querysiglen
> (int)sizeof(state
->sig
))
342 memcpy(state
->sig
, querysig
, querysiglen
);
343 state
->siglen
= querysiglen
;
348 ns_verify_tcp(u_char
*msg
, int *msglen
, ns_tcp_tsig_state
*state
,
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
;
360 if (msg
== NULL
|| msglen
== NULL
|| state
== NULL
)
364 if (state
->counter
== 0)
365 return (ns_verify(msg
, msglen
, state
->key
,
366 state
->sig
, state
->siglen
,
367 state
->sig
, &state
->siglen
, ×igned
, 0));
369 if (state
->siglen
> 0) {
370 u_int16_t siglen_n
= htons(state
->siglen
);
372 dst_verify_data(SIG_MODE_INIT
, state
->key
, &state
->ctx
,
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);
381 cp
= recstart
= ns_find_tsig(msg
, eom
);
383 if (recstart
== NULL
) {
385 return (NS_TSIG_ERROR_NO_TSIG
);
386 dst_verify_data(SIG_MODE_UPDATE
, state
->key
, &state
->ctx
,
387 msg
, *msglen
, NULL
, 0);
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);
395 /* Read the key name. */
396 n
= dn_expand(msg
, eom
, cp
, name
, NS_MAXDNAME
);
398 return (NS_TSIG_ERROR_FORMERR
);
402 BOUNDS_CHECK(cp
, 2*NS_INT16SZ
+ NS_INT32SZ
+ NS_INT16SZ
);
404 if (type
!= ns_t_tsig
)
405 return (NS_TSIG_ERROR_NO_TSIG
);
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
);
413 /* Read the algorithm name. */
415 n
= dn_expand(msg
, eom
, cp
, alg
, NS_MAXDNAME
);
417 return (NS_TSIG_ERROR_FORMERR
);
418 if (ns_samename(alg
, NS_TSIG_ALG_HMAC_MD5
) != 1)
419 return (-ns_r_badkey
);
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
);
427 /* Read the time signed and fudge. */
428 BOUNDS_CHECK(cp
, NS_INT16SZ
+ NS_INT32SZ
+ NS_INT16SZ
);
430 NS_GET32(timesigned
, cp
);
433 /* Read the signature. */
434 BOUNDS_CHECK(cp
, NS_INT16SZ
);
435 NS_GET16(sigfieldlen
, cp
);
436 BOUNDS_CHECK(cp
, sigfieldlen
);
440 /* Read the original id and error. */
441 BOUNDS_CHECK(cp
, 2*NS_INT16SZ
);
445 /* Parse the other data. */
446 BOUNDS_CHECK(cp
, NS_INT16SZ
);
447 NS_GET16(otherfieldlen
, cp
);
448 BOUNDS_CHECK(cp
, otherfieldlen
);
452 return (NS_TSIG_ERROR_FORMERR
);
455 * Do the verification.
458 /* Digest the time signed and fudge. */
460 NS_PUT16(0, cp2
); /* Top 16 bits of time. */
461 NS_PUT32(timesigned
, cp2
);
462 NS_PUT16(NS_TSIG_FUDGE
, cp2
);
464 dst_verify_data(SIG_MODE_UPDATE
, state
->key
, &state
->ctx
,
465 buf
, cp2
- buf
, NULL
, 0);
467 n
= dst_verify_data(SIG_MODE_FINAL
, state
->key
, &state
->ctx
, NULL
, 0,
468 sigstart
, sigfieldlen
);
470 return (-ns_r_badsig
);
472 if (sigfieldlen
> sizeof(state
->sig
))
473 return (NS_TSIG_ERROR_NO_SPACE
);
475 memcpy(state
->sig
, sigstart
, sigfieldlen
);
476 state
->siglen
= sigfieldlen
;
478 /* Verify the time. */
479 if (abs(timesigned
- time(NULL
)) > fudge
)
480 return (-ns_r_badtime
);
482 *msglen
= recstart
- msg
;
484 if (error
!= ns_r_noerror
)