1 /* 2 * tsig.c -- TSIG implementation (RFC 2845). 3 * 4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 11 #include "config.h" 12 #include <stdlib.h> 13 #include <ctype.h> 14 15 #include "tsig.h" 16 #include "tsig-openssl.h" 17 #include "dns.h" 18 #include "packet.h" 19 #include "query.h" 20 #include "rbtree.h" 21 22 #if !defined(HAVE_SSL) || !defined(HAVE_CRYPTO_MEMCMP) 23 /* we need fixed time compare */ 24 #define CRYPTO_memcmp memcmp_fixedtime 25 int memcmp_fixedtime(const void *s1, const void *s2, size_t n) 26 { 27 size_t i; 28 const uint8_t* u1 = (const uint8_t*)s1; 29 const uint8_t* u2 = (const uint8_t*)s2; 30 int ret = 0, haveit = 0, bret = 0, bhaveit = 0; 31 /* this routine loops for every byte in the strings. 32 * every loop, it tests ==, < and >. All three. One succeeds, 33 * as every time it must be equal, smaller or larger. The one 34 * that succeeds has one if-comparison and two assignments. */ 35 for(i=0; i<n; i++) { 36 if(u1[i] == u2[i]) { 37 /* waste time equal to < and > statements */ 38 if(haveit) { 39 bret = -1; /* waste time */ 40 bhaveit = 1; 41 } else { 42 bret = 1; /* waste time */ 43 bhaveit = 1; 44 } 45 } 46 if(u1[i] < u2[i]) { 47 if(haveit) { 48 bret = -1; /* waste time equal to the else */ 49 bhaveit = 1; 50 } else { 51 ret = -1; 52 haveit = 1; 53 } 54 } 55 if(u1[i] > u2[i]) { 56 if(haveit) { 57 bret = 1; /* waste time equal to the else */ 58 bhaveit = 1; 59 } else { 60 ret = 1; 61 haveit = 1; 62 } 63 } 64 } 65 /* use the variables to stop the compiler from excluding them */ 66 if(bhaveit) { 67 if(bret == -2) 68 ret = 0; /* never happens */ 69 } else { 70 if(bret == -2) 71 ret = 0; /* never happens */ 72 } 73 return ret; 74 } 75 #endif 76 77 static region_type *tsig_region; 78 79 struct tsig_key_table 80 { 81 rbnode_type node; /* by dname */ 82 tsig_key_type *key; 83 }; 84 typedef struct tsig_key_table tsig_key_table_type; 85 static rbtree_type *tsig_key_table; 86 87 struct tsig_algorithm_table 88 { 89 struct tsig_algorithm_table *next; 90 tsig_algorithm_type *algorithm; 91 }; 92 typedef struct tsig_algorithm_table tsig_algorithm_table_type; 93 static tsig_algorithm_table_type *tsig_algorithm_table; 94 static size_t max_algo_digest_size = 0; 95 96 static void 97 tsig_digest_variables(tsig_record_type *tsig, int tsig_timers_only) 98 { 99 uint16_t klass = htons(CLASS_ANY); 100 uint32_t ttl = htonl(0); 101 uint16_t signed_time_high = htons(tsig->signed_time_high); 102 uint32_t signed_time_low = htonl(tsig->signed_time_low); 103 uint16_t signed_time_fudge = htons(tsig->signed_time_fudge); 104 uint16_t error_code = htons(tsig->error_code); 105 uint16_t other_size = htons(tsig->other_size); 106 107 if (!tsig_timers_only) { 108 tsig->algorithm->hmac_update(tsig->context, 109 dname_name(tsig->key_name), 110 tsig->key_name->name_size); 111 tsig->algorithm->hmac_update(tsig->context, 112 &klass, 113 sizeof(klass)); 114 tsig->algorithm->hmac_update(tsig->context, 115 &ttl, 116 sizeof(ttl)); 117 tsig->algorithm->hmac_update(tsig->context, 118 dname_name(tsig->algorithm_name), 119 tsig->algorithm_name->name_size); 120 } 121 tsig->algorithm->hmac_update(tsig->context, 122 &signed_time_high, 123 sizeof(signed_time_high)); 124 tsig->algorithm->hmac_update(tsig->context, 125 &signed_time_low, 126 sizeof(signed_time_low)); 127 tsig->algorithm->hmac_update(tsig->context, 128 &signed_time_fudge, 129 sizeof(signed_time_fudge)); 130 if (!tsig_timers_only) { 131 tsig->algorithm->hmac_update(tsig->context, 132 &error_code, 133 sizeof(error_code)); 134 tsig->algorithm->hmac_update(tsig->context, 135 &other_size, 136 sizeof(other_size)); 137 tsig->algorithm->hmac_update(tsig->context, 138 tsig->other_data, 139 tsig->other_size); 140 } 141 } 142 143 static int 144 tree_dname_compare(const void* a, const void* b) 145 { 146 return dname_compare((const dname_type*)a, (const dname_type*)b); 147 } 148 149 int 150 tsig_init(region_type *region) 151 { 152 tsig_region = region; 153 tsig_key_table = rbtree_create(region, &tree_dname_compare); 154 tsig_algorithm_table = NULL; 155 156 #if defined(HAVE_SSL) 157 return tsig_openssl_init(region); 158 #endif /* defined(HAVE_SSL) */ 159 return 1; 160 } 161 162 void 163 tsig_add_key(tsig_key_type *key) 164 { 165 tsig_key_table_type *entry = (tsig_key_table_type *) region_alloc_zero( 166 tsig_region, sizeof(tsig_key_table_type)); 167 entry->key = key; 168 entry->node.key = entry->key->name; 169 (void)rbtree_insert(tsig_key_table, &entry->node); 170 } 171 172 void 173 tsig_del_key(tsig_key_type *key) 174 { 175 tsig_key_table_type *entry; 176 if(!key) return; 177 entry = (tsig_key_table_type*)rbtree_delete(tsig_key_table, key->name); 178 if(!entry) return; 179 region_recycle(tsig_region, entry, sizeof(tsig_key_table_type)); 180 } 181 182 tsig_key_type* 183 tsig_find_key(const dname_type* name) 184 { 185 tsig_key_table_type* entry; 186 entry = (tsig_key_table_type*)rbtree_search(tsig_key_table, name); 187 if(entry) 188 return entry->key; 189 return NULL; 190 } 191 192 void 193 tsig_add_algorithm(tsig_algorithm_type *algorithm) 194 { 195 tsig_algorithm_table_type *entry 196 = (tsig_algorithm_table_type *) region_alloc( 197 tsig_region, sizeof(tsig_algorithm_table_type)); 198 entry->algorithm = algorithm; 199 entry->next = tsig_algorithm_table; 200 tsig_algorithm_table = entry; 201 if(algorithm->maximum_digest_size > max_algo_digest_size) 202 max_algo_digest_size = algorithm->maximum_digest_size; 203 } 204 205 /** 206 * compare a tsig algorithm string lowercased 207 */ 208 int 209 tsig_strlowercmp(const char* str1, const char* str2) 210 { 211 while (str1 && str2 && *str1 != '\0' && *str2 != '\0') { 212 if(tolower((unsigned char)*str1) != tolower((unsigned char)*str2)) { 213 if(tolower((unsigned char)*str1) < tolower((unsigned char)*str2)) 214 return -1; 215 return 1; 216 } 217 str1++; 218 str2++; 219 } 220 if (str1 && str2) { 221 if (*str1 == *str2) 222 return 0; 223 else if (*str1 == '\0') 224 return -1; 225 } 226 else if (!str1 && !str2) 227 return 0; 228 else if (!str1 && str2) 229 return -1; 230 return 1; 231 } 232 233 234 /* 235 * Find an HMAC algorithm based on its short name. 236 */ 237 tsig_algorithm_type * 238 tsig_get_algorithm_by_name(const char *name) 239 { 240 tsig_algorithm_table_type *algorithm_entry; 241 242 for (algorithm_entry = tsig_algorithm_table; 243 algorithm_entry; 244 algorithm_entry = algorithm_entry->next) 245 { 246 if (tsig_strlowercmp(name, algorithm_entry->algorithm->short_name) == 0) 247 { 248 return algorithm_entry->algorithm; 249 } 250 if(strncmp("hmac-", algorithm_entry->algorithm->short_name, 5) == 0 && tsig_strlowercmp(name, algorithm_entry->algorithm->short_name+5) == 0) { 251 return algorithm_entry->algorithm; 252 } 253 } 254 255 return NULL; 256 } 257 258 259 const char * 260 tsig_error(int error_code) 261 { 262 static char message[1000]; 263 264 switch (error_code) { 265 case TSIG_ERROR_NOERROR: 266 return "No Error"; 267 break; 268 case TSIG_ERROR_BADSIG: 269 return "Bad Signature"; 270 break; 271 case TSIG_ERROR_BADKEY: 272 return "Bad Key"; 273 break; 274 case TSIG_ERROR_BADTIME: 275 return "Bad Time"; 276 break; 277 default: 278 if(error_code < 16) /* DNS rcodes */ 279 return rcode2str(error_code); 280 281 snprintf(message, sizeof(message), 282 "Unknown Error %d", error_code); 283 break; 284 } 285 return message; 286 } 287 288 static void 289 tsig_cleanup(void *data) 290 { 291 tsig_record_type *tsig = (tsig_record_type *) data; 292 region_destroy(tsig->rr_region); 293 region_destroy(tsig->context_region); 294 } 295 296 void 297 tsig_create_record(tsig_record_type *tsig, region_type *region) 298 { 299 tsig_create_record_custom(tsig, region, DEFAULT_CHUNK_SIZE, 300 DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE); 301 } 302 303 void 304 tsig_create_record_custom(tsig_record_type *tsig, region_type *region, 305 size_t chunk_size, size_t large_object_size, size_t initial_cleanup_size) 306 { 307 tsig->rr_region = region_create_custom(xalloc, free, chunk_size, 308 large_object_size, initial_cleanup_size, 0); 309 tsig->context_region = region_create_custom(xalloc, free, chunk_size, 310 large_object_size, initial_cleanup_size, 0); 311 if(region) 312 region_add_cleanup(region, tsig_cleanup, tsig); 313 tsig_init_record(tsig, NULL, NULL); 314 } 315 316 void 317 tsig_delete_record(tsig_record_type* tsig, region_type* region) 318 { 319 if(region) 320 region_remove_cleanup(region, tsig_cleanup, tsig); 321 region_destroy(tsig->rr_region); 322 region_destroy(tsig->context_region); 323 } 324 325 void 326 tsig_init_record(tsig_record_type *tsig, 327 tsig_algorithm_type *algorithm, 328 tsig_key_type *key) 329 { 330 tsig->status = TSIG_NOT_PRESENT; 331 tsig->error_code = TSIG_ERROR_NOERROR; 332 tsig->position = 0; 333 tsig->response_count = 0; 334 tsig->context = NULL; 335 tsig->algorithm = algorithm; 336 tsig->key = key; 337 tsig->prior_mac_size = 0; 338 tsig->prior_mac_data = NULL; 339 region_free_all(tsig->context_region); 340 } 341 342 int 343 tsig_from_query(tsig_record_type *tsig) 344 { 345 tsig_key_type *key = NULL; 346 tsig_algorithm_table_type *algorithm_entry; 347 tsig_algorithm_type *algorithm = NULL; 348 uint64_t current_time; 349 uint64_t signed_time; 350 351 assert(tsig->status == TSIG_OK); 352 assert(!tsig->algorithm); 353 assert(!tsig->key); 354 355 key = (tsig_key_type*)tsig_find_key(tsig->key_name); 356 357 for (algorithm_entry = tsig_algorithm_table; 358 algorithm_entry; 359 algorithm_entry = algorithm_entry->next) 360 { 361 if (dname_compare( 362 tsig->algorithm_name, 363 algorithm_entry->algorithm->wireformat_name) == 0) 364 { 365 algorithm = algorithm_entry->algorithm; 366 break; 367 } 368 } 369 370 if (!algorithm || !key) { 371 /* Algorithm or key is unknown, cannot authenticate. */ 372 tsig->error_code = TSIG_ERROR_BADKEY; 373 return 0; 374 } 375 376 if ((tsig->algorithm && algorithm != tsig->algorithm) 377 || (tsig->key && key != tsig->key)) 378 { 379 /* 380 * Algorithm or key changed during a single connection, 381 * return error. 382 */ 383 tsig->error_code = TSIG_ERROR_BADKEY; 384 return 0; 385 } 386 387 signed_time = ((((uint64_t) tsig->signed_time_high) << 32) | 388 ((uint64_t) tsig->signed_time_low)); 389 390 current_time = (uint64_t) time(NULL); 391 if ((current_time < signed_time - tsig->signed_time_fudge) 392 || (current_time > signed_time + tsig->signed_time_fudge)) 393 { 394 uint16_t current_time_high; 395 uint32_t current_time_low; 396 397 #if 0 /* debug */ 398 char current_time_text[26]; 399 char signed_time_text[26]; 400 time_t clock; 401 402 clock = (time_t) current_time; 403 ctime_r(&clock, current_time_text); 404 current_time_text[24] = '\0'; 405 406 clock = (time_t) signed_time; 407 ctime_r(&clock, signed_time_text); 408 signed_time_text[24] = '\0'; 409 410 log_msg(LOG_ERR, 411 "current server time %s is outside the range of TSIG" 412 " signed time %s with fudge %u", 413 current_time_text, 414 signed_time_text, 415 (unsigned) tsig->signed_time_fudge); 416 #endif 417 418 tsig->error_code = TSIG_ERROR_BADTIME; 419 current_time_high = (uint16_t) (current_time >> 32); 420 current_time_low = (uint32_t) current_time; 421 tsig->other_size = 6; 422 tsig->other_data = (uint8_t *) region_alloc( 423 tsig->rr_region, sizeof(uint16_t) + sizeof(uint32_t)); 424 write_uint16(tsig->other_data, current_time_high); 425 write_uint32(tsig->other_data + 2, current_time_low); 426 return 0; 427 } 428 429 tsig->algorithm = algorithm; 430 tsig->key = key; 431 tsig->response_count = 0; 432 tsig->prior_mac_size = 0; 433 434 return 1; 435 } 436 437 void 438 tsig_init_query(tsig_record_type *tsig, uint16_t original_query_id) 439 { 440 assert(tsig); 441 assert(tsig->algorithm); 442 assert(tsig->key); 443 444 tsig->response_count = 0; 445 tsig->prior_mac_size = 0; 446 tsig->algorithm_name = tsig->algorithm->wireformat_name; 447 tsig->key_name = tsig->key->name; 448 tsig->mac_size = 0; 449 tsig->mac_data = NULL; 450 tsig->original_query_id = original_query_id; 451 tsig->error_code = TSIG_ERROR_NOERROR; 452 tsig->other_size = 0; 453 tsig->other_data = NULL; 454 } 455 456 void 457 tsig_prepare(tsig_record_type *tsig) 458 { 459 if (!tsig->context) { 460 assert(tsig->algorithm); 461 tsig->context = tsig->algorithm->hmac_create_context( 462 tsig->context_region); 463 tsig->prior_mac_data = (uint8_t *) region_alloc( 464 tsig->context_region, 465 tsig->algorithm->maximum_digest_size); 466 } 467 tsig->algorithm->hmac_init_context(tsig->context, 468 tsig->algorithm, 469 tsig->key); 470 471 if (tsig->prior_mac_size > 0) { 472 uint16_t mac_size = htons(tsig->prior_mac_size); 473 tsig->algorithm->hmac_update(tsig->context, 474 &mac_size, 475 sizeof(mac_size)); 476 tsig->algorithm->hmac_update(tsig->context, 477 tsig->prior_mac_data, 478 tsig->prior_mac_size); 479 } 480 481 tsig->updates_since_last_prepare = 0; 482 } 483 484 void 485 tsig_update(tsig_record_type *tsig, buffer_type *packet, size_t length) 486 { 487 uint16_t original_query_id = htons(tsig->original_query_id); 488 489 assert(length <= buffer_limit(packet)); 490 491 tsig->algorithm->hmac_update(tsig->context, 492 &original_query_id, 493 sizeof(original_query_id)); 494 tsig->algorithm->hmac_update( 495 tsig->context, 496 buffer_at(packet, sizeof(original_query_id)), 497 length - sizeof(original_query_id)); 498 if (QR(packet)) { 499 ++tsig->response_count; 500 } 501 502 ++tsig->updates_since_last_prepare; 503 } 504 505 void 506 tsig_sign(tsig_record_type *tsig) 507 { 508 uint64_t current_time = (uint64_t) time(NULL); 509 tsig->signed_time_high = (uint16_t) (current_time >> 32); 510 tsig->signed_time_low = (uint32_t) current_time; 511 tsig->signed_time_fudge = 300; /* XXX; hardcoded value */ 512 513 tsig_digest_variables(tsig, tsig->response_count > 1); 514 515 tsig->algorithm->hmac_final(tsig->context, 516 tsig->prior_mac_data, 517 &tsig->prior_mac_size); 518 519 tsig->mac_size = tsig->prior_mac_size; 520 tsig->mac_data = tsig->prior_mac_data; 521 } 522 523 int 524 tsig_verify(tsig_record_type *tsig) 525 { 526 tsig_digest_variables(tsig, tsig->response_count > 1); 527 528 tsig->algorithm->hmac_final(tsig->context, 529 tsig->prior_mac_data, 530 &tsig->prior_mac_size); 531 532 if (tsig->mac_size != tsig->prior_mac_size 533 || CRYPTO_memcmp(tsig->mac_data, 534 tsig->prior_mac_data, 535 tsig->mac_size) != 0) 536 { 537 /* Digest is incorrect, cannot authenticate. */ 538 tsig->error_code = TSIG_ERROR_BADSIG; 539 return 0; 540 } else { 541 return 1; 542 } 543 } 544 545 int 546 tsig_find_rr(tsig_record_type *tsig, buffer_type *packet) 547 { 548 size_t saved_position = buffer_position(packet); 549 size_t rrcount = (QDCOUNT(packet) 550 + ANCOUNT(packet) 551 + NSCOUNT(packet) 552 + ARCOUNT(packet)); 553 size_t i; 554 int result; 555 556 if (ARCOUNT(packet) == 0) { 557 tsig->status = TSIG_NOT_PRESENT; 558 return 1; 559 } 560 561 buffer_set_position(packet, QHEADERSZ); 562 563 /* TSIG must be the last record, so skip all others. */ 564 for (i = 0; i < rrcount - 1; ++i) { 565 if (!packet_skip_rr(packet, i < QDCOUNT(packet))) { 566 buffer_set_position(packet, saved_position); 567 return 0; 568 } 569 } 570 571 result = tsig_parse_rr(tsig, packet); 572 buffer_set_position(packet, saved_position); 573 return result; 574 } 575 576 int 577 tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet) 578 { 579 uint16_t type; 580 uint16_t klass; 581 uint32_t ttl; 582 uint16_t rdlen; 583 584 tsig->status = TSIG_NOT_PRESENT; 585 tsig->position = buffer_position(packet); 586 tsig->key_name = NULL; 587 tsig->algorithm_name = NULL; 588 tsig->mac_data = NULL; 589 tsig->other_data = NULL; 590 region_free_all(tsig->rr_region); 591 592 tsig->key_name = dname_make_from_packet(tsig->rr_region, packet, 1, 1); 593 if (!tsig->key_name) { 594 buffer_set_position(packet, tsig->position); 595 return 0; 596 } 597 598 if (!buffer_available(packet, 10)) { 599 buffer_set_position(packet, tsig->position); 600 return 0; 601 } 602 603 type = buffer_read_u16(packet); 604 klass = buffer_read_u16(packet); 605 606 /* TSIG not present */ 607 if (type != TYPE_TSIG || klass != CLASS_ANY) { 608 buffer_set_position(packet, tsig->position); 609 return 1; 610 } 611 612 ttl = buffer_read_u32(packet); 613 rdlen = buffer_read_u16(packet); 614 615 tsig->status = TSIG_ERROR; 616 tsig->error_code = RCODE_FORMAT; 617 if (ttl != 0 || !buffer_available(packet, rdlen)) { 618 buffer_set_position(packet, tsig->position); 619 return 0; 620 } 621 622 tsig->algorithm_name = dname_make_from_packet( 623 tsig->rr_region, packet, 1, 1); 624 if (!tsig->algorithm_name || !buffer_available(packet, 10)) { 625 buffer_set_position(packet, tsig->position); 626 return 0; 627 } 628 629 tsig->signed_time_high = buffer_read_u16(packet); 630 tsig->signed_time_low = buffer_read_u32(packet); 631 tsig->signed_time_fudge = buffer_read_u16(packet); 632 tsig->mac_size = buffer_read_u16(packet); 633 if (!buffer_available(packet, tsig->mac_size)) { 634 buffer_set_position(packet, tsig->position); 635 tsig->mac_size = 0; 636 return 0; 637 } 638 tsig->mac_data = (uint8_t *) region_alloc_init( 639 tsig->rr_region, buffer_current(packet), tsig->mac_size); 640 buffer_skip(packet, tsig->mac_size); 641 if (!buffer_available(packet, 6)) { 642 buffer_set_position(packet, tsig->position); 643 return 0; 644 } 645 tsig->original_query_id = buffer_read_u16(packet); 646 tsig->error_code = buffer_read_u16(packet); 647 tsig->other_size = buffer_read_u16(packet); 648 if (!buffer_available(packet, tsig->other_size) || tsig->other_size > 16) { 649 tsig->other_size = 0; 650 buffer_set_position(packet, tsig->position); 651 return 0; 652 } 653 tsig->other_data = (uint8_t *) region_alloc_init( 654 tsig->rr_region, buffer_current(packet), tsig->other_size); 655 buffer_skip(packet, tsig->other_size); 656 tsig->status = TSIG_OK; 657 return 1; 658 } 659 660 void 661 tsig_append_rr(tsig_record_type *tsig, buffer_type *packet) 662 { 663 size_t rdlength_pos; 664 665 /* XXX: TODO key name compression? */ 666 if(tsig->key_name) 667 buffer_write(packet, dname_name(tsig->key_name), 668 tsig->key_name->name_size); 669 else buffer_write_u8(packet, 0); 670 buffer_write_u16(packet, TYPE_TSIG); 671 buffer_write_u16(packet, CLASS_ANY); 672 buffer_write_u32(packet, 0); /* TTL */ 673 rdlength_pos = buffer_position(packet); 674 buffer_skip(packet, sizeof(uint16_t)); 675 if(tsig->algorithm_name) 676 buffer_write(packet, dname_name(tsig->algorithm_name), 677 tsig->algorithm_name->name_size); 678 else buffer_write_u8(packet, 0); 679 buffer_write_u16(packet, tsig->signed_time_high); 680 buffer_write_u32(packet, tsig->signed_time_low); 681 buffer_write_u16(packet, tsig->signed_time_fudge); 682 buffer_write_u16(packet, tsig->mac_size); 683 buffer_write(packet, tsig->mac_data, tsig->mac_size); 684 buffer_write_u16(packet, tsig->original_query_id); 685 buffer_write_u16(packet, tsig->error_code); 686 buffer_write_u16(packet, tsig->other_size); 687 buffer_write(packet, tsig->other_data, tsig->other_size); 688 689 buffer_write_u16_at(packet, rdlength_pos, 690 buffer_position(packet) - rdlength_pos 691 - sizeof(uint16_t)); 692 } 693 694 size_t 695 tsig_reserved_space(tsig_record_type *tsig) 696 { 697 if (tsig->status == TSIG_NOT_PRESENT) 698 return 0; 699 700 return ( 701 (tsig->key_name?tsig->key_name->name_size:1) /* Owner */ 702 + sizeof(uint16_t) /* Type */ 703 + sizeof(uint16_t) /* Class */ 704 + sizeof(uint32_t) /* TTL */ 705 + sizeof(uint16_t) /* RDATA length */ 706 + (tsig->algorithm_name?tsig->algorithm_name->name_size:1) 707 + sizeof(uint16_t) /* Signed time (high) */ 708 + sizeof(uint32_t) /* Signed time (low) */ 709 + sizeof(uint16_t) /* Signed time fudge */ 710 + sizeof(uint16_t) /* MAC size */ 711 + max_algo_digest_size /* MAC data */ 712 + sizeof(uint16_t) /* Original query ID */ 713 + sizeof(uint16_t) /* Error code */ 714 + sizeof(uint16_t) /* Other size */ 715 + tsig->other_size); /* Other data */ 716 } 717 718 void 719 tsig_error_reply(tsig_record_type *tsig) 720 { 721 if(tsig->mac_data) 722 memset(tsig->mac_data, 0, tsig->mac_size); 723 tsig->mac_size = 0; 724 } 725 726 void 727 tsig_finalize() 728 { 729 #if defined(HAVE_SSL) 730 tsig_openssl_finalize(); 731 #endif /* defined(HAVE_SSL) */ 732 } 733