1 /* 2 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright (c) 1999 by Internet Software Consortium, Inc. 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 16 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 18 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 19 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 20 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 21 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 22 * SOFTWARE. 23 */ 24 25 #ifndef lint 26 static const char rcsid[] = "$Id: ns_verify.c,v 8.14 2001/05/29 05:49:40 marka Exp $"; 27 #endif 28 29 /* Import. */ 30 31 #include "port_before.h" 32 #include "fd_setsize.h" 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 37 #include <netinet/in.h> 38 #include <arpa/nameser.h> 39 #include <arpa/inet.h> 40 41 #include <errno.h> 42 #include <netdb.h> 43 #include <resolv.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <time.h> 48 #include <unistd.h> 49 50 #include <isc/dst.h> 51 52 #include "port_after.h" 53 54 /* Private. */ 55 56 #define BOUNDS_CHECK(ptr, count) \ 57 do { \ 58 if ((ptr) + (count) > eom) { \ 59 return (NS_TSIG_ERROR_FORMERR); \ 60 } \ 61 } while (0) 62 63 /* Public. */ 64 65 u_char * 66 ns_find_tsig(u_char *msg, u_char *eom) { 67 HEADER *hp = (HEADER *)msg; 68 int n, type; 69 u_char *cp = msg, *start; 70 71 if (msg == NULL || eom == NULL || msg > eom) 72 return (NULL); 73 74 if (cp + HFIXEDSZ >= eom) 75 return (NULL); 76 77 if (hp->arcount == 0) 78 return (NULL); 79 80 cp += HFIXEDSZ; 81 82 n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount)); 83 if (n < 0) 84 return (NULL); 85 cp += n; 86 87 n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount)); 88 if (n < 0) 89 return (NULL); 90 cp += n; 91 92 n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount)); 93 if (n < 0) 94 return (NULL); 95 cp += n; 96 97 n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1); 98 if (n < 0) 99 return (NULL); 100 cp += n; 101 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); 109 110 GETSHORT(type, cp); 111 if (type != ns_t_tsig) 112 return (NULL); 113 return (start); 114 } 115 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 127 * 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) 139 */ 140 int 141 ns_verify(u_char *msg, int *msglen, void *k, 142 const u_char *querysig, int querysiglen, u_char *sig, int *siglen, 143 time_t *timesigned, int nostrip) 144 { 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 int n; 152 int error; 153 u_int16_t type, length; 154 u_int16_t fudge, sigfieldlen, id, otherfieldlen; 155 156 dst_init(); 157 if (msg == NULL || msglen == NULL || *msglen < 0) 158 return (-1); 159 160 eom = msg + *msglen; 161 162 recstart = ns_find_tsig(msg, eom); 163 if (recstart == NULL) 164 return (NS_TSIG_ERROR_NO_TSIG); 165 166 cp = recstart; 167 168 /* Read the key name. */ 169 n = dn_expand(msg, eom, cp, name, MAXDNAME); 170 if (n < 0) 171 return (NS_TSIG_ERROR_FORMERR); 172 cp += n; 173 174 /* Read the type. */ 175 BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); 176 GETSHORT(type, cp); 177 if (type != ns_t_tsig) 178 return (NS_TSIG_ERROR_NO_TSIG); 179 180 /* Skip the class and TTL, save the length. */ 181 cp += INT16SZ + INT32SZ; 182 GETSHORT(length, cp); 183 if (eom - cp != length) 184 return (NS_TSIG_ERROR_FORMERR); 185 186 /* Read the algorithm name. */ 187 rdatastart = cp; 188 n = dn_expand(msg, eom, cp, alg, MAXDNAME); 189 if (n < 0) 190 return (NS_TSIG_ERROR_FORMERR); 191 if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) 192 return (-ns_r_badkey); 193 cp += n; 194 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); 200 201 /* Read the signature. */ 202 BOUNDS_CHECK(cp, INT16SZ); 203 GETSHORT(sigfieldlen, cp); 204 BOUNDS_CHECK(cp, sigfieldlen); 205 sigstart = cp; 206 cp += sigfieldlen; 207 208 /* Read the original id and error. */ 209 BOUNDS_CHECK(cp, 2*INT16SZ); 210 GETSHORT(id, cp); 211 GETSHORT(error, cp); 212 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; 219 220 if (cp != eom) 221 return (NS_TSIG_ERROR_FORMERR); 222 223 /* Verify that the key used is OK. */ 224 if (key != NULL) { 225 if (key->dk_alg != KEY_HMAC_MD5) 226 return (-ns_r_badkey); 227 if (error != ns_r_badsig && error != ns_r_badkey) { 228 if (ns_samename(key->dk_key_name, name) != 1) 229 return (-ns_r_badkey); 230 } 231 } 232 233 hp->arcount = htons(ntohs(hp->arcount) - 1); 234 235 /* 236 * Do the verification. 237 */ 238 239 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { 240 void *ctx; 241 u_char buf[MAXDNAME]; 242 u_char buf2[MAXDNAME]; 243 244 /* Digest the query signature, if this is a response. */ 245 dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); 246 if (querysiglen > 0 && querysig != NULL) { 247 u_int16_t len_n = htons(querysiglen); 248 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 249 (u_char *)&len_n, INT16SZ, NULL, 0); 250 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 251 querysig, querysiglen, NULL, 0); 252 } 253 254 /* Digest the message. */ 255 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg, 256 NULL, 0); 257 258 /* Digest the key name. */ 259 n = ns_name_pton(name, buf2, sizeof(buf2)); 260 if (n < 0) 261 return (-1); 262 n = ns_name_ntol(buf2, buf, sizeof(buf)); 263 if (n < 0) 264 return (-1); 265 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 266 267 /* Digest the class and TTL. */ 268 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 269 recstart + dn_skipname(recstart, eom) + INT16SZ, 270 INT16SZ + INT32SZ, NULL, 0); 271 272 /* Digest the algorithm. */ 273 n = ns_name_pton(alg, buf2, sizeof(buf2)); 274 if (n < 0) 275 return (-1); 276 n = ns_name_ntol(buf2, buf, sizeof(buf)); 277 if (n < 0) 278 return (-1); 279 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 280 281 /* Digest the time signed and fudge. */ 282 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 283 rdatastart + dn_skipname(rdatastart, eom), 284 INT16SZ + INT32SZ + INT16SZ, NULL, 0); 285 286 /* Digest the error and other data. */ 287 dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 288 otherstart - INT16SZ - INT16SZ, 289 otherfieldlen + INT16SZ + INT16SZ, NULL, 0); 290 291 n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, 292 sigstart, sigfieldlen); 293 294 if (n < 0) 295 return (-ns_r_badsig); 296 297 if (sig != NULL && siglen != NULL) { 298 if (*siglen < sigfieldlen) 299 return (NS_TSIG_ERROR_NO_SPACE); 300 memcpy(sig, sigstart, sigfieldlen); 301 *siglen = sigfieldlen; 302 } 303 } else { 304 if (sigfieldlen > 0) 305 return (NS_TSIG_ERROR_FORMERR); 306 if (sig != NULL && siglen != NULL) 307 *siglen = 0; 308 } 309 310 /* Reset the counter, since we still need to check for badtime. */ 311 hp->arcount = htons(ntohs(hp->arcount) + 1); 312 313 /* Verify the time. */ 314 if (abs((*timesigned) - time(NULL)) > fudge) 315 return (-ns_r_badtime); 316 317 if (nostrip == 0) { 318 *msglen = recstart - msg; 319 hp->arcount = htons(ntohs(hp->arcount) - 1); 320 } 321 322 if (error != NOERROR) 323 return (error); 324 325 return (0); 326 } 327 328 int 329 ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen, 330 ns_tcp_tsig_state *state) 331 { 332 dst_init(); 333 if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) 334 return (-1); 335 state->counter = -1; 336 state->key = k; 337 if (state->key->dk_alg != KEY_HMAC_MD5) 338 return (-ns_r_badkey); 339 if (querysiglen > (int)sizeof(state->sig)) 340 return (-1); 341 memcpy(state->sig, querysig, querysiglen); 342 state->siglen = querysiglen; 343 return (0); 344 } 345 346 int 347 ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state, 348 int required) 349 { 350 HEADER *hp = (HEADER *)msg; 351 u_char *recstart, *rdatastart, *sigstart; 352 unsigned int sigfieldlen, otherfieldlen; 353 u_char *cp, *eom = msg + *msglen, *cp2; 354 char name[MAXDNAME], alg[MAXDNAME]; 355 u_char buf[MAXDNAME]; 356 int n, type, length, fudge, id, error; 357 time_t timesigned; 358 359 if (msg == NULL || msglen == NULL || state == NULL) 360 return (-1); 361 362 state->counter++; 363 if (state->counter == 0) 364 return (ns_verify(msg, msglen, state->key, 365 state->sig, state->siglen, 366 state->sig, &state->siglen, ×igned, 0)); 367 368 if (state->siglen > 0) { 369 u_int16_t siglen_n = htons(state->siglen); 370 371 dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx, 372 NULL, 0, NULL, 0); 373 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 374 (u_char *)&siglen_n, INT16SZ, NULL, 0); 375 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 376 state->sig, state->siglen, NULL, 0); 377 state->siglen = 0; 378 } 379 380 cp = recstart = ns_find_tsig(msg, eom); 381 382 if (recstart == NULL) { 383 if (required) 384 return (NS_TSIG_ERROR_NO_TSIG); 385 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 386 msg, *msglen, NULL, 0); 387 return (0); 388 } 389 390 hp->arcount = htons(ntohs(hp->arcount) - 1); 391 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 392 msg, recstart - msg, NULL, 0); 393 394 /* Read the key name. */ 395 n = dn_expand(msg, eom, cp, name, MAXDNAME); 396 if (n < 0) 397 return (NS_TSIG_ERROR_FORMERR); 398 cp += n; 399 400 /* Read the type. */ 401 BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); 402 GETSHORT(type, cp); 403 if (type != ns_t_tsig) 404 return (NS_TSIG_ERROR_NO_TSIG); 405 406 /* Skip the class and TTL, save the length. */ 407 cp += INT16SZ + INT32SZ; 408 GETSHORT(length, cp); 409 if (eom - cp != length) 410 return (NS_TSIG_ERROR_FORMERR); 411 412 /* Read the algorithm name. */ 413 rdatastart = cp; 414 n = dn_expand(msg, eom, cp, alg, MAXDNAME); 415 if (n < 0) 416 return (NS_TSIG_ERROR_FORMERR); 417 if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) 418 return (-ns_r_badkey); 419 cp += n; 420 421 /* Verify that the key used is OK. */ 422 if ((ns_samename(state->key->dk_key_name, name) != 1 || 423 state->key->dk_alg != KEY_HMAC_MD5)) 424 return (-ns_r_badkey); 425 426 /* Read the time signed and fudge. */ 427 BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); 428 cp += INT16SZ; 429 GETLONG(timesigned, cp); 430 GETSHORT(fudge, cp); 431 432 /* Read the signature. */ 433 BOUNDS_CHECK(cp, INT16SZ); 434 GETSHORT(sigfieldlen, cp); 435 BOUNDS_CHECK(cp, sigfieldlen); 436 sigstart = cp; 437 cp += sigfieldlen; 438 439 /* Read the original id and error. */ 440 BOUNDS_CHECK(cp, 2*INT16SZ); 441 GETSHORT(id, cp); 442 GETSHORT(error, cp); 443 444 /* Parse the other data. */ 445 BOUNDS_CHECK(cp, INT16SZ); 446 GETSHORT(otherfieldlen, cp); 447 BOUNDS_CHECK(cp, otherfieldlen); 448 cp += otherfieldlen; 449 450 if (cp != eom) 451 return (NS_TSIG_ERROR_FORMERR); 452 453 /* 454 * Do the verification. 455 */ 456 457 /* Digest the time signed and fudge. */ 458 cp2 = buf; 459 PUTSHORT(0, cp2); /* Top 16 bits of time. */ 460 PUTLONG(timesigned, cp2); 461 PUTSHORT(NS_TSIG_FUDGE, cp2); 462 463 dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 464 buf, cp2 - buf, NULL, 0); 465 466 n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, 467 sigstart, sigfieldlen); 468 if (n < 0) 469 return (-ns_r_badsig); 470 471 if (sigfieldlen > sizeof(state->sig)) 472 return (NS_TSIG_ERROR_NO_SPACE); 473 474 memcpy(state->sig, sigstart, sigfieldlen); 475 state->siglen = sigfieldlen; 476 477 /* Verify the time. */ 478 if (abs(timesigned - time(NULL)) > fudge) 479 return (-ns_r_badtime); 480 481 *msglen = recstart - msg; 482 483 if (error != NOERROR) 484 return (error); 485 486 return (0); 487 } 488