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 20static 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 66u_char * 67ns_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 */ 141int 142ns_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 329int 330ns_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 347int 348ns_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, ×igned, 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} 489