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 25int 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 77static region_type *tsig_region; 78 79struct tsig_key_table 80{ 81 rbnode_type node; /* by dname */ 82 tsig_key_type *key; 83}; 84typedef struct tsig_key_table tsig_key_table_type; 85static rbtree_type *tsig_key_table; 86 87struct tsig_algorithm_table 88{ 89 struct tsig_algorithm_table *next; 90 tsig_algorithm_type *algorithm; 91}; 92typedef struct tsig_algorithm_table tsig_algorithm_table_type; 93static tsig_algorithm_table_type *tsig_algorithm_table; 94static size_t max_algo_digest_size = 0; 95 96static void 97tsig_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 143static int 144tree_dname_compare(const void* a, const void* b) 145{ 146 return dname_compare((const dname_type*)a, (const dname_type*)b); 147} 148 149int 150tsig_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 162void 163tsig_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 172void 173tsig_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 182tsig_key_type* 183tsig_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 192void 193tsig_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 */ 208int 209tsig_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 */ 237tsig_algorithm_type * 238tsig_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 259const char * 260tsig_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 288static void 289tsig_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 296void 297tsig_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 303void 304tsig_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 316void 317tsig_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 325void 326tsig_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 342int 343tsig_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 437void 438tsig_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 456void 457tsig_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 484void 485tsig_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 505void 506tsig_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 523int 524tsig_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 545int 546tsig_find_rr(tsig_record_type *tsig, buffer_type *packet) 547{ 548 size_t saved_position = buffer_position(packet); 549 size_t rrcount = ((size_t)QDCOUNT(packet) 550 + (size_t)ANCOUNT(packet) 551 + (size_t)NSCOUNT(packet) 552 + (size_t)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 if(rrcount > 65530) { 561 /* impossibly high number of records in 64k, reject packet */ 562 buffer_set_position(packet, saved_position); 563 return 0; 564 } 565 566 buffer_set_position(packet, QHEADERSZ); 567 568 /* TSIG must be the last record, so skip all others. */ 569 for (i = 0; i < rrcount - 1; ++i) { 570 if (!packet_skip_rr(packet, i < QDCOUNT(packet))) { 571 buffer_set_position(packet, saved_position); 572 return 0; 573 } 574 } 575 576 result = tsig_parse_rr(tsig, packet); 577 buffer_set_position(packet, saved_position); 578 return result; 579} 580 581int 582tsig_parse_rr(tsig_record_type *tsig, buffer_type *packet) 583{ 584 uint16_t type; 585 uint16_t klass; 586 uint32_t ttl; 587 uint16_t rdlen; 588 589 tsig->status = TSIG_NOT_PRESENT; 590 tsig->position = buffer_position(packet); 591 tsig->key_name = NULL; 592 tsig->algorithm_name = NULL; 593 tsig->mac_data = NULL; 594 tsig->other_data = NULL; 595 region_free_all(tsig->rr_region); 596 597 tsig->key_name = dname_make_from_packet(tsig->rr_region, packet, 1, 1); 598 if (!tsig->key_name) { 599 buffer_set_position(packet, tsig->position); 600 return 0; 601 } 602 603 if (!buffer_available(packet, 10)) { 604 buffer_set_position(packet, tsig->position); 605 return 0; 606 } 607 608 type = buffer_read_u16(packet); 609 klass = buffer_read_u16(packet); 610 611 /* TSIG not present */ 612 if (type != TYPE_TSIG || klass != CLASS_ANY) { 613 buffer_set_position(packet, tsig->position); 614 return 1; 615 } 616 617 ttl = buffer_read_u32(packet); 618 rdlen = buffer_read_u16(packet); 619 620 tsig->status = TSIG_ERROR; 621 tsig->error_code = RCODE_FORMAT; 622 if (ttl != 0 || !buffer_available(packet, rdlen)) { 623 buffer_set_position(packet, tsig->position); 624 return 0; 625 } 626 627 tsig->algorithm_name = dname_make_from_packet( 628 tsig->rr_region, packet, 1, 1); 629 if (!tsig->algorithm_name || !buffer_available(packet, 10)) { 630 buffer_set_position(packet, tsig->position); 631 return 0; 632 } 633 634 tsig->signed_time_high = buffer_read_u16(packet); 635 tsig->signed_time_low = buffer_read_u32(packet); 636 tsig->signed_time_fudge = buffer_read_u16(packet); 637 tsig->mac_size = buffer_read_u16(packet); 638 if (!buffer_available(packet, tsig->mac_size)) { 639 buffer_set_position(packet, tsig->position); 640 tsig->mac_size = 0; 641 return 0; 642 } 643 if(tsig->mac_size > 16384) { 644 /* the hash should not be too big, really 512/8=64 bytes */ 645 buffer_set_position(packet, tsig->position); 646 tsig->mac_size = 0; 647 return 0; 648 } 649 tsig->mac_data = (uint8_t *) region_alloc_init( 650 tsig->rr_region, buffer_current(packet), tsig->mac_size); 651 buffer_skip(packet, tsig->mac_size); 652 if (!buffer_available(packet, 6)) { 653 buffer_set_position(packet, tsig->position); 654 return 0; 655 } 656 tsig->original_query_id = buffer_read_u16(packet); 657 tsig->error_code = buffer_read_u16(packet); 658 tsig->other_size = buffer_read_u16(packet); 659 if (!buffer_available(packet, tsig->other_size) || tsig->other_size > 16) { 660 tsig->other_size = 0; 661 buffer_set_position(packet, tsig->position); 662 return 0; 663 } 664 tsig->other_data = (uint8_t *) region_alloc_init( 665 tsig->rr_region, buffer_current(packet), tsig->other_size); 666 buffer_skip(packet, tsig->other_size); 667 tsig->status = TSIG_OK; 668 return 1; 669} 670 671void 672tsig_append_rr(tsig_record_type *tsig, buffer_type *packet) 673{ 674 size_t rdlength_pos; 675 676 /* XXX: TODO key name compression? */ 677 if(tsig->key_name) 678 buffer_write(packet, dname_name(tsig->key_name), 679 tsig->key_name->name_size); 680 else buffer_write_u8(packet, 0); 681 buffer_write_u16(packet, TYPE_TSIG); 682 buffer_write_u16(packet, CLASS_ANY); 683 buffer_write_u32(packet, 0); /* TTL */ 684 rdlength_pos = buffer_position(packet); 685 buffer_skip(packet, sizeof(uint16_t)); 686 if(tsig->algorithm_name) 687 buffer_write(packet, dname_name(tsig->algorithm_name), 688 tsig->algorithm_name->name_size); 689 else buffer_write_u8(packet, 0); 690 buffer_write_u16(packet, tsig->signed_time_high); 691 buffer_write_u32(packet, tsig->signed_time_low); 692 buffer_write_u16(packet, tsig->signed_time_fudge); 693 buffer_write_u16(packet, tsig->mac_size); 694 buffer_write(packet, tsig->mac_data, tsig->mac_size); 695 buffer_write_u16(packet, tsig->original_query_id); 696 buffer_write_u16(packet, tsig->error_code); 697 buffer_write_u16(packet, tsig->other_size); 698 buffer_write(packet, tsig->other_data, tsig->other_size); 699 700 buffer_write_u16_at(packet, rdlength_pos, 701 buffer_position(packet) - rdlength_pos 702 - sizeof(uint16_t)); 703} 704 705size_t 706tsig_reserved_space(tsig_record_type *tsig) 707{ 708 if (tsig->status == TSIG_NOT_PRESENT) 709 return 0; 710 711 return ( 712 (tsig->key_name?tsig->key_name->name_size:1) /* Owner */ 713 + sizeof(uint16_t) /* Type */ 714 + sizeof(uint16_t) /* Class */ 715 + sizeof(uint32_t) /* TTL */ 716 + sizeof(uint16_t) /* RDATA length */ 717 + (tsig->algorithm_name?tsig->algorithm_name->name_size:1) 718 + sizeof(uint16_t) /* Signed time (high) */ 719 + sizeof(uint32_t) /* Signed time (low) */ 720 + sizeof(uint16_t) /* Signed time fudge */ 721 + sizeof(uint16_t) /* MAC size */ 722 + max_algo_digest_size /* MAC data */ 723 + sizeof(uint16_t) /* Original query ID */ 724 + sizeof(uint16_t) /* Error code */ 725 + sizeof(uint16_t) /* Other size */ 726 + tsig->other_size); /* Other data */ 727} 728 729void 730tsig_error_reply(tsig_record_type *tsig) 731{ 732 if(tsig->mac_data) 733 memset(tsig->mac_data, 0, tsig->mac_size); 734 tsig->mac_size = 0; 735} 736 737void 738tsig_finalize() 739{ 740#if defined(HAVE_SSL) 741 tsig_openssl_finalize(); 742#endif /* defined(HAVE_SSL) */ 743} 744