1 /* $NetBSD: tkey.c,v 1.12 2022/09/23 12:15:30 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <inttypes.h> 19 #include <stdbool.h> 20 21 #include <isc/buffer.h> 22 #include <isc/md.h> 23 #include <isc/mem.h> 24 #include <isc/nonce.h> 25 #include <isc/print.h> 26 #include <isc/random.h> 27 #include <isc/string.h> 28 #include <isc/util.h> 29 30 #include <pk11/site.h> 31 32 #include <dns/dnssec.h> 33 #include <dns/fixedname.h> 34 #include <dns/keyvalues.h> 35 #include <dns/log.h> 36 #include <dns/message.h> 37 #include <dns/name.h> 38 #include <dns/rdata.h> 39 #include <dns/rdatalist.h> 40 #include <dns/rdataset.h> 41 #include <dns/rdatastruct.h> 42 #include <dns/result.h> 43 #include <dns/tkey.h> 44 #include <dns/tsig.h> 45 46 #include <dst/dst.h> 47 #include <dst/gssapi.h> 48 49 #include "dst_internal.h" 50 51 #define TEMP_BUFFER_SZ 8192 52 #define TKEY_RANDOM_AMOUNT 16 53 54 #if USE_PKCS11 55 #include <pk11/pk11.h> 56 #endif /* if USE_PKCS11 */ 57 58 #define RETERR(x) \ 59 do { \ 60 result = (x); \ 61 if (result != ISC_R_SUCCESS) \ 62 goto failure; \ 63 } while (0) 64 65 static void 66 tkey_log(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2); 67 68 static void 69 tkey_log(const char *fmt, ...) { 70 va_list ap; 71 72 va_start(ap, fmt); 73 isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST, 74 ISC_LOG_DEBUG(4), fmt, ap); 75 va_end(ap); 76 } 77 78 static void 79 dumpmessage(dns_message_t *msg) { 80 isc_buffer_t outbuf; 81 unsigned char *output; 82 int len = TEMP_BUFFER_SZ; 83 isc_result_t result; 84 85 for (;;) { 86 output = isc_mem_get(msg->mctx, len); 87 88 isc_buffer_init(&outbuf, output, len); 89 result = dns_message_totext(msg, &dns_master_style_debug, 0, 90 &outbuf); 91 if (result == ISC_R_NOSPACE) { 92 isc_mem_put(msg->mctx, output, len); 93 len *= 2; 94 continue; 95 } 96 97 if (result == ISC_R_SUCCESS) { 98 tkey_log("%.*s", (int)isc_buffer_usedlength(&outbuf), 99 (char *)isc_buffer_base(&outbuf)); 100 } else { 101 tkey_log("Warning: dns_message_totext: %s", 102 dns_result_totext(result)); 103 } 104 break; 105 } 106 107 if (output != NULL) { 108 isc_mem_put(msg->mctx, output, len); 109 } 110 } 111 112 isc_result_t 113 dns_tkeyctx_create(isc_mem_t *mctx, dns_tkeyctx_t **tctxp) { 114 dns_tkeyctx_t *tctx; 115 116 REQUIRE(mctx != NULL); 117 REQUIRE(tctxp != NULL && *tctxp == NULL); 118 119 tctx = isc_mem_get(mctx, sizeof(dns_tkeyctx_t)); 120 tctx->mctx = NULL; 121 isc_mem_attach(mctx, &tctx->mctx); 122 tctx->dhkey = NULL; 123 tctx->domain = NULL; 124 tctx->gsscred = NULL; 125 tctx->gssapi_keytab = NULL; 126 127 *tctxp = tctx; 128 return (ISC_R_SUCCESS); 129 } 130 131 void 132 dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp) { 133 isc_mem_t *mctx; 134 dns_tkeyctx_t *tctx; 135 136 REQUIRE(tctxp != NULL && *tctxp != NULL); 137 138 tctx = *tctxp; 139 *tctxp = NULL; 140 mctx = tctx->mctx; 141 142 if (tctx->dhkey != NULL) { 143 dst_key_free(&tctx->dhkey); 144 } 145 if (tctx->domain != NULL) { 146 if (dns_name_dynamic(tctx->domain)) { 147 dns_name_free(tctx->domain, mctx); 148 } 149 isc_mem_put(mctx, tctx->domain, sizeof(dns_name_t)); 150 } 151 if (tctx->gssapi_keytab != NULL) { 152 isc_mem_free(mctx, tctx->gssapi_keytab); 153 } 154 if (tctx->gsscred != NULL) { 155 dst_gssapi_releasecred(&tctx->gsscred); 156 } 157 isc_mem_putanddetach(&mctx, tctx, sizeof(dns_tkeyctx_t)); 158 } 159 160 static isc_result_t 161 add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata, 162 uint32_t ttl, dns_namelist_t *namelist) { 163 isc_result_t result; 164 isc_region_t r, newr; 165 dns_rdata_t *newrdata = NULL; 166 dns_name_t *newname = NULL; 167 dns_rdatalist_t *newlist = NULL; 168 dns_rdataset_t *newset = NULL; 169 isc_buffer_t *tmprdatabuf = NULL; 170 171 RETERR(dns_message_gettemprdata(msg, &newrdata)); 172 173 dns_rdata_toregion(rdata, &r); 174 isc_buffer_allocate(msg->mctx, &tmprdatabuf, r.length); 175 isc_buffer_availableregion(tmprdatabuf, &newr); 176 memmove(newr.base, r.base, r.length); 177 dns_rdata_fromregion(newrdata, rdata->rdclass, rdata->type, &newr); 178 dns_message_takebuffer(msg, &tmprdatabuf); 179 180 RETERR(dns_message_gettempname(msg, &newname)); 181 dns_name_copynf(name, newname); 182 183 RETERR(dns_message_gettemprdatalist(msg, &newlist)); 184 newlist->rdclass = newrdata->rdclass; 185 newlist->type = newrdata->type; 186 newlist->ttl = ttl; 187 ISC_LIST_APPEND(newlist->rdata, newrdata, link); 188 189 RETERR(dns_message_gettemprdataset(msg, &newset)); 190 RETERR(dns_rdatalist_tordataset(newlist, newset)); 191 192 ISC_LIST_INIT(newname->list); 193 ISC_LIST_APPEND(newname->list, newset, link); 194 195 ISC_LIST_APPEND(*namelist, newname, link); 196 197 return (ISC_R_SUCCESS); 198 199 failure: 200 if (newrdata != NULL) { 201 if (ISC_LINK_LINKED(newrdata, link)) { 202 INSIST(newlist != NULL); 203 ISC_LIST_UNLINK(newlist->rdata, newrdata, link); 204 } 205 dns_message_puttemprdata(msg, &newrdata); 206 } 207 if (newname != NULL) { 208 dns_message_puttempname(msg, &newname); 209 } 210 if (newset != NULL) { 211 dns_rdataset_disassociate(newset); 212 dns_message_puttemprdataset(msg, &newset); 213 } 214 if (newlist != NULL) { 215 dns_message_puttemprdatalist(msg, &newlist); 216 } 217 return (result); 218 } 219 220 static void 221 free_namelist(dns_message_t *msg, dns_namelist_t *namelist) { 222 dns_name_t *name; 223 dns_rdataset_t *set; 224 225 while (!ISC_LIST_EMPTY(*namelist)) { 226 name = ISC_LIST_HEAD(*namelist); 227 ISC_LIST_UNLINK(*namelist, name, link); 228 while (!ISC_LIST_EMPTY(name->list)) { 229 set = ISC_LIST_HEAD(name->list); 230 ISC_LIST_UNLINK(name->list, set, link); 231 if (dns_rdataset_isassociated(set)) { 232 dns_rdataset_disassociate(set); 233 } 234 dns_message_puttemprdataset(msg, &set); 235 } 236 dns_message_puttempname(msg, &name); 237 } 238 } 239 240 static isc_result_t 241 compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness, 242 isc_region_t *serverrandomness, isc_buffer_t *secret) { 243 isc_md_t *md; 244 isc_region_t r, r2; 245 unsigned char digests[ISC_MAX_MD_SIZE * 2]; 246 unsigned char *digest1, *digest2; 247 unsigned int digestslen, digestlen1 = 0, digestlen2 = 0; 248 unsigned int i; 249 isc_result_t result; 250 251 isc_buffer_usedregion(shared, &r); 252 253 md = isc_md_new(); 254 if (md == NULL) { 255 return (ISC_R_NOSPACE); 256 } 257 258 /* 259 * MD5 ( query data | DH value ). 260 */ 261 digest1 = digests; 262 263 result = isc_md_init(md, ISC_MD_MD5); 264 if (result != ISC_R_SUCCESS) { 265 goto end; 266 } 267 268 result = isc_md_update(md, queryrandomness->base, 269 queryrandomness->length); 270 if (result != ISC_R_SUCCESS) { 271 goto end; 272 } 273 274 result = isc_md_update(md, r.base, r.length); 275 if (result != ISC_R_SUCCESS) { 276 goto end; 277 } 278 279 result = isc_md_final(md, digest1, &digestlen1); 280 if (result != ISC_R_SUCCESS) { 281 goto end; 282 } 283 284 result = isc_md_reset(md); 285 if (result != ISC_R_SUCCESS) { 286 goto end; 287 } 288 289 /* 290 * MD5 ( server data | DH value ). 291 */ 292 digest2 = digests + digestlen1; 293 294 result = isc_md_init(md, ISC_MD_MD5); 295 if (result != ISC_R_SUCCESS) { 296 goto end; 297 } 298 299 result = isc_md_update(md, serverrandomness->base, 300 serverrandomness->length); 301 if (result != ISC_R_SUCCESS) { 302 goto end; 303 } 304 305 result = isc_md_update(md, r.base, r.length); 306 if (result != ISC_R_SUCCESS) { 307 goto end; 308 } 309 310 result = isc_md_final(md, digest2, &digestlen2); 311 if (result != ISC_R_SUCCESS) { 312 goto end; 313 } 314 315 isc_md_free(md); 316 md = NULL; 317 318 digestslen = digestlen1 + digestlen2; 319 320 /* 321 * XOR ( DH value, MD5-1 | MD5-2). 322 */ 323 isc_buffer_availableregion(secret, &r); 324 isc_buffer_usedregion(shared, &r2); 325 if (r.length < digestslen || r.length < r2.length) { 326 return (ISC_R_NOSPACE); 327 } 328 if (r2.length > digestslen) { 329 memmove(r.base, r2.base, r2.length); 330 for (i = 0; i < digestslen; i++) { 331 r.base[i] ^= digests[i]; 332 } 333 isc_buffer_add(secret, r2.length); 334 } else { 335 memmove(r.base, digests, digestslen); 336 for (i = 0; i < r2.length; i++) { 337 r.base[i] ^= r2.base[i]; 338 } 339 isc_buffer_add(secret, digestslen); 340 } 341 result = ISC_R_SUCCESS; 342 end: 343 if (md != NULL) { 344 isc_md_free(md); 345 } 346 return (result); 347 } 348 349 static isc_result_t 350 process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, 351 dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx, 352 dns_rdata_tkey_t *tkeyout, dns_tsig_keyring_t *ring, 353 dns_namelist_t *namelist) { 354 isc_result_t result = ISC_R_SUCCESS; 355 dns_name_t *keyname, ourname; 356 dns_rdataset_t *keyset = NULL; 357 dns_rdata_t keyrdata = DNS_RDATA_INIT, ourkeyrdata = DNS_RDATA_INIT; 358 bool found_key = false, found_incompatible = false; 359 dst_key_t *pubkey = NULL; 360 isc_buffer_t ourkeybuf, *shared = NULL; 361 isc_region_t r, r2, ourkeyr; 362 unsigned char keydata[DST_KEY_MAXSIZE]; 363 unsigned int sharedsize; 364 isc_buffer_t secret; 365 unsigned char *randomdata = NULL, secretdata[256]; 366 dns_ttl_t ttl = 0; 367 368 if (tctx->dhkey == NULL) { 369 tkey_log("process_dhtkey: tkey-dhkey not defined"); 370 tkeyout->error = dns_tsigerror_badalg; 371 return (DNS_R_REFUSED); 372 } 373 374 if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) { 375 tkey_log("process_dhtkey: algorithms other than " 376 "hmac-md5 are not supported"); 377 tkeyout->error = dns_tsigerror_badalg; 378 return (ISC_R_SUCCESS); 379 } 380 381 /* 382 * Look for a DH KEY record that will work with ours. 383 */ 384 for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL); 385 result == ISC_R_SUCCESS && !found_key; 386 result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) 387 { 388 keyname = NULL; 389 dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname); 390 keyset = NULL; 391 result = dns_message_findtype(keyname, dns_rdatatype_key, 0, 392 &keyset); 393 if (result != ISC_R_SUCCESS) { 394 continue; 395 } 396 397 for (result = dns_rdataset_first(keyset); 398 result == ISC_R_SUCCESS && !found_key; 399 result = dns_rdataset_next(keyset)) 400 { 401 dns_rdataset_current(keyset, &keyrdata); 402 pubkey = NULL; 403 result = dns_dnssec_keyfromrdata(keyname, &keyrdata, 404 msg->mctx, &pubkey); 405 if (result != ISC_R_SUCCESS) { 406 dns_rdata_reset(&keyrdata); 407 continue; 408 } 409 if (dst_key_alg(pubkey) == DNS_KEYALG_DH) { 410 if (dst_key_paramcompare(pubkey, tctx->dhkey)) { 411 found_key = true; 412 ttl = keyset->ttl; 413 break; 414 } else { 415 found_incompatible = true; 416 } 417 } 418 dst_key_free(&pubkey); 419 dns_rdata_reset(&keyrdata); 420 } 421 } 422 423 if (!found_key) { 424 if (found_incompatible) { 425 tkey_log("process_dhtkey: found an incompatible key"); 426 tkeyout->error = dns_tsigerror_badkey; 427 return (ISC_R_SUCCESS); 428 } else { 429 tkey_log("process_dhtkey: failed to find a key"); 430 return (DNS_R_FORMERR); 431 } 432 } 433 434 RETERR(add_rdata_to_list(msg, keyname, &keyrdata, ttl, namelist)); 435 436 isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata)); 437 RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf)); 438 isc_buffer_usedregion(&ourkeybuf, &ourkeyr); 439 dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_any, 440 dns_rdatatype_key, &ourkeyr); 441 442 dns_name_init(&ourname, NULL); 443 dns_name_clone(dst_key_name(tctx->dhkey), &ourname); 444 445 /* 446 * XXXBEW The TTL should be obtained from the database, if it exists. 447 */ 448 RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, 0, namelist)); 449 450 RETERR(dst_key_secretsize(tctx->dhkey, &sharedsize)); 451 isc_buffer_allocate(msg->mctx, &shared, sharedsize); 452 453 result = dst_key_computesecret(pubkey, tctx->dhkey, shared); 454 if (result != ISC_R_SUCCESS) { 455 tkey_log("process_dhtkey: failed to compute shared secret: %s", 456 isc_result_totext(result)); 457 goto failure; 458 } 459 dst_key_free(&pubkey); 460 461 isc_buffer_init(&secret, secretdata, sizeof(secretdata)); 462 463 randomdata = isc_mem_get(tkeyout->mctx, TKEY_RANDOM_AMOUNT); 464 465 isc_nonce_buf(randomdata, TKEY_RANDOM_AMOUNT); 466 467 r.base = randomdata; 468 r.length = TKEY_RANDOM_AMOUNT; 469 r2.base = tkeyin->key; 470 r2.length = tkeyin->keylen; 471 RETERR(compute_secret(shared, &r2, &r, &secret)); 472 isc_buffer_free(&shared); 473 474 RETERR(dns_tsigkey_create( 475 name, &tkeyin->algorithm, isc_buffer_base(&secret), 476 isc_buffer_usedlength(&secret), true, signer, tkeyin->inception, 477 tkeyin->expire, ring->mctx, ring, NULL)); 478 479 /* This key is good for a long time */ 480 tkeyout->inception = tkeyin->inception; 481 tkeyout->expire = tkeyin->expire; 482 483 tkeyout->key = randomdata; 484 tkeyout->keylen = TKEY_RANDOM_AMOUNT; 485 486 return (ISC_R_SUCCESS); 487 488 failure: 489 if (!ISC_LIST_EMPTY(*namelist)) { 490 free_namelist(msg, namelist); 491 } 492 if (shared != NULL) { 493 isc_buffer_free(&shared); 494 } 495 if (pubkey != NULL) { 496 dst_key_free(&pubkey); 497 } 498 if (randomdata != NULL) { 499 isc_mem_put(tkeyout->mctx, randomdata, TKEY_RANDOM_AMOUNT); 500 } 501 return (result); 502 } 503 504 static isc_result_t 505 process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin, 506 dns_tkeyctx_t *tctx, dns_rdata_tkey_t *tkeyout, 507 dns_tsig_keyring_t *ring) { 508 isc_result_t result = ISC_R_SUCCESS; 509 dst_key_t *dstkey = NULL; 510 dns_tsigkey_t *tsigkey = NULL; 511 dns_fixedname_t fixed; 512 dns_name_t *principal; 513 isc_stdtime_t now; 514 isc_region_t intoken; 515 isc_buffer_t *outtoken = NULL; 516 dns_gss_ctx_id_t gss_ctx = NULL; 517 518 /* 519 * You have to define either a gss credential (principal) to 520 * accept with tkey-gssapi-credential, or you have to 521 * configure a specific keytab (with tkey-gssapi-keytab) in 522 * order to use gsstkey. 523 */ 524 if (tctx->gsscred == NULL && tctx->gssapi_keytab == NULL) { 525 tkey_log("process_gsstkey(): no tkey-gssapi-credential " 526 "or tkey-gssapi-keytab configured"); 527 return (ISC_R_NOPERM); 528 } 529 530 if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) && 531 !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) 532 { 533 tkeyout->error = dns_tsigerror_badalg; 534 tkey_log("process_gsstkey(): dns_tsigerror_badalg"); /* XXXSRA 535 */ 536 return (ISC_R_SUCCESS); 537 } 538 539 /* 540 * XXXDCL need to check for key expiry per 4.1.1 541 * XXXDCL need a way to check fully established, perhaps w/key_flags 542 */ 543 544 intoken.base = tkeyin->key; 545 intoken.length = tkeyin->keylen; 546 547 result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring); 548 if (result == ISC_R_SUCCESS) { 549 gss_ctx = dst_key_getgssctx(tsigkey->key); 550 } 551 552 principal = dns_fixedname_initname(&fixed); 553 554 /* 555 * Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set 556 */ 557 result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab, 558 &intoken, &outtoken, &gss_ctx, principal, 559 tctx->mctx); 560 if (result == DNS_R_INVALIDTKEY) { 561 if (tsigkey != NULL) { 562 dns_tsigkey_detach(&tsigkey); 563 } 564 tkeyout->error = dns_tsigerror_badkey; 565 tkey_log("process_gsstkey(): dns_tsigerror_badkey"); /* XXXSRA 566 */ 567 return (ISC_R_SUCCESS); 568 } 569 if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) { 570 goto failure; 571 } 572 /* 573 * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times. 574 */ 575 576 isc_stdtime_get(&now); 577 578 if (dns_name_countlabels(principal) == 0U) { 579 if (tsigkey != NULL) { 580 dns_tsigkey_detach(&tsigkey); 581 } 582 } else if (tsigkey == NULL) { 583 #ifdef GSSAPI 584 OM_uint32 gret, minor, lifetime; 585 #endif /* ifdef GSSAPI */ 586 uint32_t expire; 587 588 RETERR(dst_key_fromgssapi(name, gss_ctx, ring->mctx, &dstkey, 589 &intoken)); 590 /* 591 * Limit keys to 1 hour or the context's lifetime whichever 592 * is smaller. 593 */ 594 expire = now + 3600; 595 #ifdef GSSAPI 596 gret = gss_context_time(&minor, gss_ctx, &lifetime); 597 if (gret == GSS_S_COMPLETE && now + lifetime < expire) { 598 expire = now + lifetime; 599 } 600 #endif /* ifdef GSSAPI */ 601 RETERR(dns_tsigkey_createfromkey( 602 name, &tkeyin->algorithm, dstkey, true, principal, now, 603 expire, ring->mctx, ring, &tsigkey)); 604 dst_key_free(&dstkey); 605 tkeyout->inception = now; 606 tkeyout->expire = expire; 607 } else { 608 tkeyout->inception = tsigkey->inception; 609 tkeyout->expire = tsigkey->expire; 610 } 611 612 if (outtoken) { 613 tkeyout->key = isc_mem_get(tkeyout->mctx, 614 isc_buffer_usedlength(outtoken)); 615 tkeyout->keylen = isc_buffer_usedlength(outtoken); 616 memmove(tkeyout->key, isc_buffer_base(outtoken), 617 isc_buffer_usedlength(outtoken)); 618 isc_buffer_free(&outtoken); 619 } else { 620 tkeyout->key = isc_mem_get(tkeyout->mctx, tkeyin->keylen); 621 tkeyout->keylen = tkeyin->keylen; 622 memmove(tkeyout->key, tkeyin->key, tkeyin->keylen); 623 } 624 625 tkeyout->error = dns_rcode_noerror; 626 627 tkey_log("process_gsstkey(): dns_tsigerror_noerror"); /* XXXSRA */ 628 629 /* 630 * We found a TKEY to respond with. If the request is not TSIG signed, 631 * we need to make sure the response is signed (see RFC 3645, Section 632 * 2.2). 633 */ 634 if (tsigkey != NULL) { 635 if (msg->tsigkey == NULL && msg->sig0key == NULL) { 636 dns_message_settsigkey(msg, tsigkey); 637 } 638 dns_tsigkey_detach(&tsigkey); 639 } 640 641 return (ISC_R_SUCCESS); 642 643 failure: 644 if (tsigkey != NULL) { 645 dns_tsigkey_detach(&tsigkey); 646 } 647 648 if (dstkey != NULL) { 649 dst_key_free(&dstkey); 650 } 651 652 if (outtoken != NULL) { 653 isc_buffer_free(&outtoken); 654 } 655 656 tkey_log("process_gsstkey(): %s", isc_result_totext(result)); /* XXXSRA 657 */ 658 659 return (result); 660 } 661 662 static isc_result_t 663 process_deletetkey(dns_name_t *signer, dns_name_t *name, 664 dns_rdata_tkey_t *tkeyin, dns_rdata_tkey_t *tkeyout, 665 dns_tsig_keyring_t *ring) { 666 isc_result_t result; 667 dns_tsigkey_t *tsigkey = NULL; 668 const dns_name_t *identity; 669 670 result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring); 671 if (result != ISC_R_SUCCESS) { 672 tkeyout->error = dns_tsigerror_badname; 673 return (ISC_R_SUCCESS); 674 } 675 676 /* 677 * Only allow a delete if the identity that created the key is the 678 * same as the identity that signed the message. 679 */ 680 identity = dns_tsigkey_identity(tsigkey); 681 if (identity == NULL || !dns_name_equal(identity, signer)) { 682 dns_tsigkey_detach(&tsigkey); 683 return (DNS_R_REFUSED); 684 } 685 686 /* 687 * Set the key to be deleted when no references are left. If the key 688 * was not generated with TKEY and is in the config file, it may be 689 * reloaded later. 690 */ 691 dns_tsigkey_setdeleted(tsigkey); 692 693 /* Release the reference */ 694 dns_tsigkey_detach(&tsigkey); 695 696 return (ISC_R_SUCCESS); 697 } 698 699 isc_result_t 700 dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, 701 dns_tsig_keyring_t *ring) { 702 isc_result_t result = ISC_R_SUCCESS; 703 dns_rdata_tkey_t tkeyin, tkeyout; 704 bool freetkeyin = false; 705 dns_name_t *qname, *name, *keyname, *signer, tsigner; 706 dns_fixedname_t fkeyname; 707 dns_rdataset_t *tkeyset; 708 dns_rdata_t rdata; 709 dns_namelist_t namelist; 710 char tkeyoutdata[512]; 711 isc_buffer_t tkeyoutbuf; 712 713 REQUIRE(msg != NULL); 714 REQUIRE(tctx != NULL); 715 REQUIRE(ring != NULL); 716 717 ISC_LIST_INIT(namelist); 718 719 /* 720 * Interpret the question section. 721 */ 722 result = dns_message_firstname(msg, DNS_SECTION_QUESTION); 723 if (result != ISC_R_SUCCESS) { 724 return (DNS_R_FORMERR); 725 } 726 727 qname = NULL; 728 dns_message_currentname(msg, DNS_SECTION_QUESTION, &qname); 729 730 /* 731 * Look for a TKEY record that matches the question. 732 */ 733 tkeyset = NULL; 734 name = NULL; 735 result = dns_message_findname(msg, DNS_SECTION_ADDITIONAL, qname, 736 dns_rdatatype_tkey, 0, &name, &tkeyset); 737 if (result != ISC_R_SUCCESS) { 738 /* 739 * Try the answer section, since that's where Win2000 740 * puts it. 741 */ 742 name = NULL; 743 if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 744 dns_rdatatype_tkey, 0, &name, 745 &tkeyset) != ISC_R_SUCCESS) 746 { 747 result = DNS_R_FORMERR; 748 tkey_log("dns_tkey_processquery: couldn't find a TKEY " 749 "matching the question"); 750 goto failure; 751 } 752 } 753 result = dns_rdataset_first(tkeyset); 754 if (result != ISC_R_SUCCESS) { 755 result = DNS_R_FORMERR; 756 goto failure; 757 } 758 dns_rdata_init(&rdata); 759 dns_rdataset_current(tkeyset, &rdata); 760 761 RETERR(dns_rdata_tostruct(&rdata, &tkeyin, NULL)); 762 freetkeyin = true; 763 764 if (tkeyin.error != dns_rcode_noerror) { 765 result = DNS_R_FORMERR; 766 goto failure; 767 } 768 769 /* 770 * Before we go any farther, verify that the message was signed. 771 * GSSAPI TKEY doesn't require a signature, the rest do. 772 */ 773 dns_name_init(&tsigner, NULL); 774 result = dns_message_signer(msg, &tsigner); 775 if (result != ISC_R_SUCCESS) { 776 if (tkeyin.mode == DNS_TKEYMODE_GSSAPI && 777 result == ISC_R_NOTFOUND) { 778 signer = NULL; 779 } else { 780 tkey_log("dns_tkey_processquery: query was not " 781 "properly signed - rejecting"); 782 result = DNS_R_FORMERR; 783 goto failure; 784 } 785 } else { 786 signer = &tsigner; 787 } 788 789 tkeyout.common.rdclass = tkeyin.common.rdclass; 790 tkeyout.common.rdtype = tkeyin.common.rdtype; 791 ISC_LINK_INIT(&tkeyout.common, link); 792 tkeyout.mctx = msg->mctx; 793 794 dns_name_init(&tkeyout.algorithm, NULL); 795 dns_name_clone(&tkeyin.algorithm, &tkeyout.algorithm); 796 797 tkeyout.inception = tkeyout.expire = 0; 798 tkeyout.mode = tkeyin.mode; 799 tkeyout.error = 0; 800 tkeyout.keylen = tkeyout.otherlen = 0; 801 tkeyout.key = tkeyout.other = NULL; 802 803 /* 804 * A delete operation must have a fully specified key name. If this 805 * is not a delete, we do the following: 806 * if (qname != ".") 807 * keyname = qname + defaultdomain 808 * else 809 * keyname = <random hex> + defaultdomain 810 */ 811 if (tkeyin.mode != DNS_TKEYMODE_DELETE) { 812 dns_tsigkey_t *tsigkey = NULL; 813 814 if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) 815 { 816 tkey_log("dns_tkey_processquery: tkey-domain not set"); 817 result = DNS_R_REFUSED; 818 goto failure; 819 } 820 821 keyname = dns_fixedname_initname(&fkeyname); 822 823 if (!dns_name_equal(qname, dns_rootname)) { 824 unsigned int n = dns_name_countlabels(qname); 825 dns_name_copynf(qname, keyname); 826 dns_name_getlabelsequence(keyname, 0, n - 1, keyname); 827 } else { 828 static char hexdigits[16] = { '0', '1', '2', '3', 829 '4', '5', '6', '7', 830 '8', '9', 'A', 'B', 831 'C', 'D', 'E', 'F' }; 832 unsigned char randomdata[16]; 833 char randomtext[32]; 834 isc_buffer_t b; 835 unsigned int i, j; 836 837 isc_nonce_buf(randomdata, sizeof(randomdata)); 838 839 for (i = 0, j = 0; i < sizeof(randomdata); i++) { 840 unsigned char val = randomdata[i]; 841 randomtext[j++] = hexdigits[val >> 4]; 842 randomtext[j++] = hexdigits[val & 0xF]; 843 } 844 isc_buffer_init(&b, randomtext, sizeof(randomtext)); 845 isc_buffer_add(&b, sizeof(randomtext)); 846 result = dns_name_fromtext(keyname, &b, NULL, 0, NULL); 847 if (result != ISC_R_SUCCESS) { 848 goto failure; 849 } 850 } 851 852 if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) { 853 /* Yup. This is a hack */ 854 result = dns_name_concatenate(keyname, dns_rootname, 855 keyname, NULL); 856 if (result != ISC_R_SUCCESS) { 857 goto failure; 858 } 859 } else { 860 result = dns_name_concatenate(keyname, tctx->domain, 861 keyname, NULL); 862 if (result != ISC_R_SUCCESS) { 863 goto failure; 864 } 865 } 866 867 result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring); 868 869 if (result == ISC_R_SUCCESS) { 870 tkeyout.error = dns_tsigerror_badname; 871 dns_tsigkey_detach(&tsigkey); 872 goto failure_with_tkey; 873 } else if (result != ISC_R_NOTFOUND) { 874 goto failure; 875 } 876 } else { 877 keyname = qname; 878 } 879 880 switch (tkeyin.mode) { 881 case DNS_TKEYMODE_DIFFIEHELLMAN: 882 tkeyout.error = dns_rcode_noerror; 883 RETERR(process_dhtkey(msg, signer, keyname, &tkeyin, tctx, 884 &tkeyout, ring, &namelist)); 885 break; 886 case DNS_TKEYMODE_GSSAPI: 887 tkeyout.error = dns_rcode_noerror; 888 RETERR(process_gsstkey(msg, keyname, &tkeyin, tctx, &tkeyout, 889 ring)); 890 break; 891 case DNS_TKEYMODE_DELETE: 892 tkeyout.error = dns_rcode_noerror; 893 RETERR(process_deletetkey(signer, keyname, &tkeyin, &tkeyout, 894 ring)); 895 break; 896 case DNS_TKEYMODE_SERVERASSIGNED: 897 case DNS_TKEYMODE_RESOLVERASSIGNED: 898 result = DNS_R_NOTIMP; 899 goto failure; 900 default: 901 tkeyout.error = dns_tsigerror_badmode; 902 } 903 904 failure_with_tkey: 905 906 dns_rdata_init(&rdata); 907 isc_buffer_init(&tkeyoutbuf, tkeyoutdata, sizeof(tkeyoutdata)); 908 result = dns_rdata_fromstruct(&rdata, tkeyout.common.rdclass, 909 tkeyout.common.rdtype, &tkeyout, 910 &tkeyoutbuf); 911 912 if (freetkeyin) { 913 dns_rdata_freestruct(&tkeyin); 914 freetkeyin = false; 915 } 916 917 if (tkeyout.key != NULL) { 918 isc_mem_put(tkeyout.mctx, tkeyout.key, tkeyout.keylen); 919 } 920 if (tkeyout.other != NULL) { 921 isc_mem_put(tkeyout.mctx, tkeyout.other, tkeyout.otherlen); 922 } 923 if (result != ISC_R_SUCCESS) { 924 goto failure; 925 } 926 927 RETERR(add_rdata_to_list(msg, keyname, &rdata, 0, &namelist)); 928 929 RETERR(dns_message_reply(msg, true)); 930 931 name = ISC_LIST_HEAD(namelist); 932 while (name != NULL) { 933 dns_name_t *next = ISC_LIST_NEXT(name, link); 934 ISC_LIST_UNLINK(namelist, name, link); 935 dns_message_addname(msg, name, DNS_SECTION_ANSWER); 936 name = next; 937 } 938 939 return (ISC_R_SUCCESS); 940 941 failure: 942 943 if (freetkeyin) { 944 dns_rdata_freestruct(&tkeyin); 945 } 946 if (!ISC_LIST_EMPTY(namelist)) { 947 free_namelist(msg, &namelist); 948 } 949 return (result); 950 } 951 952 static isc_result_t 953 buildquery(dns_message_t *msg, const dns_name_t *name, dns_rdata_tkey_t *tkey, 954 bool win2k) { 955 dns_name_t *qname = NULL, *aname = NULL; 956 dns_rdataset_t *question = NULL, *tkeyset = NULL; 957 dns_rdatalist_t *tkeylist = NULL; 958 dns_rdata_t *rdata = NULL; 959 isc_buffer_t *dynbuf = NULL; 960 isc_result_t result; 961 unsigned int len; 962 963 REQUIRE(msg != NULL); 964 REQUIRE(name != NULL); 965 REQUIRE(tkey != NULL); 966 967 RETERR(dns_message_gettempname(msg, &qname)); 968 RETERR(dns_message_gettempname(msg, &aname)); 969 970 RETERR(dns_message_gettemprdataset(msg, &question)); 971 dns_rdataset_makequestion(question, dns_rdataclass_any, 972 dns_rdatatype_tkey); 973 974 len = 16 + tkey->algorithm.length + tkey->keylen + tkey->otherlen; 975 isc_buffer_allocate(msg->mctx, &dynbuf, len); 976 RETERR(dns_message_gettemprdata(msg, &rdata)); 977 978 RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any, 979 dns_rdatatype_tkey, tkey, dynbuf)); 980 dns_message_takebuffer(msg, &dynbuf); 981 982 RETERR(dns_message_gettemprdatalist(msg, &tkeylist)); 983 tkeylist->rdclass = dns_rdataclass_any; 984 tkeylist->type = dns_rdatatype_tkey; 985 ISC_LIST_APPEND(tkeylist->rdata, rdata, link); 986 987 RETERR(dns_message_gettemprdataset(msg, &tkeyset)); 988 RETERR(dns_rdatalist_tordataset(tkeylist, tkeyset)); 989 990 dns_name_copynf(name, qname); 991 dns_name_copynf(name, aname); 992 993 ISC_LIST_APPEND(qname->list, question, link); 994 ISC_LIST_APPEND(aname->list, tkeyset, link); 995 996 dns_message_addname(msg, qname, DNS_SECTION_QUESTION); 997 998 /* 999 * Windows 2000 needs this in the answer section, not the additional 1000 * section where the RFC specifies. 1001 */ 1002 if (win2k) { 1003 dns_message_addname(msg, aname, DNS_SECTION_ANSWER); 1004 } else { 1005 dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL); 1006 } 1007 1008 return (ISC_R_SUCCESS); 1009 1010 failure: 1011 if (qname != NULL) { 1012 dns_message_puttempname(msg, &qname); 1013 } 1014 if (aname != NULL) { 1015 dns_message_puttempname(msg, &aname); 1016 } 1017 if (question != NULL) { 1018 dns_rdataset_disassociate(question); 1019 dns_message_puttemprdataset(msg, &question); 1020 } 1021 if (dynbuf != NULL) { 1022 isc_buffer_free(&dynbuf); 1023 } 1024 if (rdata != NULL) { 1025 dns_message_puttemprdata(msg, &rdata); 1026 } 1027 if (tkeylist != NULL) { 1028 dns_message_puttemprdatalist(msg, &tkeylist); 1029 } 1030 if (tkeyset != NULL) { 1031 if (dns_rdataset_isassociated(tkeyset)) { 1032 dns_rdataset_disassociate(tkeyset); 1033 } 1034 dns_message_puttemprdataset(msg, &tkeyset); 1035 } 1036 return (result); 1037 } 1038 1039 isc_result_t 1040 dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, 1041 const dns_name_t *name, const dns_name_t *algorithm, 1042 isc_buffer_t *nonce, uint32_t lifetime) { 1043 dns_rdata_tkey_t tkey; 1044 dns_rdata_t *rdata = NULL; 1045 isc_buffer_t *dynbuf = NULL; 1046 isc_region_t r; 1047 dns_name_t keyname; 1048 dns_namelist_t namelist; 1049 isc_result_t result; 1050 isc_stdtime_t now; 1051 dns_name_t *item; 1052 1053 REQUIRE(msg != NULL); 1054 REQUIRE(key != NULL); 1055 REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 1056 REQUIRE(dst_key_isprivate(key)); 1057 REQUIRE(name != NULL); 1058 REQUIRE(algorithm != NULL); 1059 1060 tkey.common.rdclass = dns_rdataclass_any; 1061 tkey.common.rdtype = dns_rdatatype_tkey; 1062 ISC_LINK_INIT(&tkey.common, link); 1063 tkey.mctx = msg->mctx; 1064 dns_name_init(&tkey.algorithm, NULL); 1065 dns_name_clone(algorithm, &tkey.algorithm); 1066 isc_stdtime_get(&now); 1067 tkey.inception = now; 1068 tkey.expire = now + lifetime; 1069 tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN; 1070 if (nonce != NULL) { 1071 isc_buffer_usedregion(nonce, &r); 1072 } else { 1073 r.base = NULL; 1074 r.length = 0; 1075 } 1076 tkey.error = 0; 1077 tkey.key = r.base; 1078 tkey.keylen = r.length; 1079 tkey.other = NULL; 1080 tkey.otherlen = 0; 1081 1082 RETERR(buildquery(msg, name, &tkey, false)); 1083 1084 RETERR(dns_message_gettemprdata(msg, &rdata)); 1085 isc_buffer_allocate(msg->mctx, &dynbuf, 1024); 1086 RETERR(dst_key_todns(key, dynbuf)); 1087 isc_buffer_usedregion(dynbuf, &r); 1088 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_key, &r); 1089 dns_message_takebuffer(msg, &dynbuf); 1090 1091 dns_name_init(&keyname, NULL); 1092 dns_name_clone(dst_key_name(key), &keyname); 1093 1094 ISC_LIST_INIT(namelist); 1095 RETERR(add_rdata_to_list(msg, &keyname, rdata, 0, &namelist)); 1096 item = ISC_LIST_HEAD(namelist); 1097 while (item != NULL) { 1098 dns_name_t *next = ISC_LIST_NEXT(item, link); 1099 ISC_LIST_UNLINK(namelist, item, link); 1100 dns_message_addname(msg, item, DNS_SECTION_ADDITIONAL); 1101 item = next; 1102 } 1103 1104 return (ISC_R_SUCCESS); 1105 1106 failure: 1107 1108 if (dynbuf != NULL) { 1109 isc_buffer_free(&dynbuf); 1110 } 1111 return (result); 1112 } 1113 1114 isc_result_t 1115 dns_tkey_buildgssquery(dns_message_t *msg, const dns_name_t *name, 1116 const dns_name_t *gname, isc_buffer_t *intoken, 1117 uint32_t lifetime, dns_gss_ctx_id_t *context, bool win2k, 1118 isc_mem_t *mctx, char **err_message) { 1119 dns_rdata_tkey_t tkey; 1120 isc_result_t result; 1121 isc_stdtime_t now; 1122 isc_buffer_t token; 1123 unsigned char array[TEMP_BUFFER_SZ]; 1124 1125 UNUSED(intoken); 1126 1127 REQUIRE(msg != NULL); 1128 REQUIRE(name != NULL); 1129 REQUIRE(gname != NULL); 1130 REQUIRE(context != NULL); 1131 REQUIRE(mctx != NULL); 1132 1133 isc_buffer_init(&token, array, sizeof(array)); 1134 result = dst_gssapi_initctx(gname, NULL, &token, context, mctx, 1135 err_message); 1136 if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) { 1137 return (result); 1138 } 1139 1140 tkey.common.rdclass = dns_rdataclass_any; 1141 tkey.common.rdtype = dns_rdatatype_tkey; 1142 ISC_LINK_INIT(&tkey.common, link); 1143 tkey.mctx = NULL; 1144 dns_name_init(&tkey.algorithm, NULL); 1145 1146 if (win2k) { 1147 dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); 1148 } else { 1149 dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); 1150 } 1151 1152 isc_stdtime_get(&now); 1153 tkey.inception = now; 1154 tkey.expire = now + lifetime; 1155 tkey.mode = DNS_TKEYMODE_GSSAPI; 1156 tkey.error = 0; 1157 tkey.key = isc_buffer_base(&token); 1158 tkey.keylen = isc_buffer_usedlength(&token); 1159 tkey.other = NULL; 1160 tkey.otherlen = 0; 1161 1162 return (buildquery(msg, name, &tkey, win2k)); 1163 } 1164 1165 isc_result_t 1166 dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) { 1167 dns_rdata_tkey_t tkey; 1168 1169 REQUIRE(msg != NULL); 1170 REQUIRE(key != NULL); 1171 1172 tkey.common.rdclass = dns_rdataclass_any; 1173 tkey.common.rdtype = dns_rdatatype_tkey; 1174 ISC_LINK_INIT(&tkey.common, link); 1175 tkey.mctx = msg->mctx; 1176 dns_name_init(&tkey.algorithm, NULL); 1177 dns_name_clone(key->algorithm, &tkey.algorithm); 1178 tkey.inception = tkey.expire = 0; 1179 tkey.mode = DNS_TKEYMODE_DELETE; 1180 tkey.error = 0; 1181 tkey.keylen = tkey.otherlen = 0; 1182 tkey.key = tkey.other = NULL; 1183 1184 return (buildquery(msg, &key->name, &tkey, false)); 1185 } 1186 1187 static isc_result_t 1188 find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata, 1189 int section) { 1190 dns_rdataset_t *tkeyset; 1191 isc_result_t result; 1192 1193 result = dns_message_firstname(msg, section); 1194 while (result == ISC_R_SUCCESS) { 1195 *name = NULL; 1196 dns_message_currentname(msg, section, name); 1197 tkeyset = NULL; 1198 result = dns_message_findtype(*name, dns_rdatatype_tkey, 0, 1199 &tkeyset); 1200 if (result == ISC_R_SUCCESS) { 1201 result = dns_rdataset_first(tkeyset); 1202 if (result != ISC_R_SUCCESS) { 1203 return (result); 1204 } 1205 dns_rdataset_current(tkeyset, rdata); 1206 return (ISC_R_SUCCESS); 1207 } 1208 result = dns_message_nextname(msg, section); 1209 } 1210 if (result == ISC_R_NOMORE) { 1211 return (ISC_R_NOTFOUND); 1212 } 1213 return (result); 1214 } 1215 1216 isc_result_t 1217 dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1218 dst_key_t *key, isc_buffer_t *nonce, 1219 dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring) { 1220 dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1221 dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname; 1222 dns_rdataset_t *theirkeyset = NULL, *ourkeyset = NULL; 1223 dns_rdata_t theirkeyrdata = DNS_RDATA_INIT; 1224 dst_key_t *theirkey = NULL; 1225 dns_rdata_tkey_t qtkey, rtkey; 1226 unsigned char secretdata[256]; 1227 unsigned int sharedsize; 1228 isc_buffer_t *shared = NULL, secret; 1229 isc_region_t r, r2; 1230 isc_result_t result; 1231 bool freertkey = false; 1232 1233 REQUIRE(qmsg != NULL); 1234 REQUIRE(rmsg != NULL); 1235 REQUIRE(key != NULL); 1236 REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 1237 REQUIRE(dst_key_isprivate(key)); 1238 if (outkey != NULL) { 1239 REQUIRE(*outkey == NULL); 1240 } 1241 1242 if (rmsg->rcode != dns_rcode_noerror) { 1243 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1244 } 1245 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1246 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1247 freertkey = true; 1248 1249 RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, DNS_SECTION_ADDITIONAL)); 1250 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1251 1252 if (rtkey.error != dns_rcode_noerror || 1253 rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN || 1254 rtkey.mode != qtkey.mode || 1255 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1256 rmsg->rcode != dns_rcode_noerror) 1257 { 1258 tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1259 "or error set(1)"); 1260 result = DNS_R_INVALIDTKEY; 1261 dns_rdata_freestruct(&qtkey); 1262 goto failure; 1263 } 1264 1265 dns_rdata_freestruct(&qtkey); 1266 1267 dns_name_init(&keyname, NULL); 1268 dns_name_clone(dst_key_name(key), &keyname); 1269 1270 ourkeyname = NULL; 1271 ourkeyset = NULL; 1272 RETERR(dns_message_findname(rmsg, DNS_SECTION_ANSWER, &keyname, 1273 dns_rdatatype_key, 0, &ourkeyname, 1274 &ourkeyset)); 1275 1276 result = dns_message_firstname(rmsg, DNS_SECTION_ANSWER); 1277 while (result == ISC_R_SUCCESS) { 1278 theirkeyname = NULL; 1279 dns_message_currentname(rmsg, DNS_SECTION_ANSWER, 1280 &theirkeyname); 1281 if (dns_name_equal(theirkeyname, ourkeyname)) { 1282 goto next; 1283 } 1284 theirkeyset = NULL; 1285 result = dns_message_findtype(theirkeyname, dns_rdatatype_key, 1286 0, &theirkeyset); 1287 if (result == ISC_R_SUCCESS) { 1288 RETERR(dns_rdataset_first(theirkeyset)); 1289 break; 1290 } 1291 next: 1292 result = dns_message_nextname(rmsg, DNS_SECTION_ANSWER); 1293 } 1294 1295 if (theirkeyset == NULL) { 1296 tkey_log("dns_tkey_processdhresponse: failed to find server " 1297 "key"); 1298 result = ISC_R_NOTFOUND; 1299 goto failure; 1300 } 1301 1302 dns_rdataset_current(theirkeyset, &theirkeyrdata); 1303 RETERR(dns_dnssec_keyfromrdata(theirkeyname, &theirkeyrdata, rmsg->mctx, 1304 &theirkey)); 1305 1306 RETERR(dst_key_secretsize(key, &sharedsize)); 1307 isc_buffer_allocate(rmsg->mctx, &shared, sharedsize); 1308 1309 RETERR(dst_key_computesecret(theirkey, key, shared)); 1310 1311 isc_buffer_init(&secret, secretdata, sizeof(secretdata)); 1312 1313 r.base = rtkey.key; 1314 r.length = rtkey.keylen; 1315 if (nonce != NULL) { 1316 isc_buffer_usedregion(nonce, &r2); 1317 } else { 1318 r2.base = NULL; 1319 r2.length = 0; 1320 } 1321 RETERR(compute_secret(shared, &r2, &r, &secret)); 1322 1323 isc_buffer_usedregion(&secret, &r); 1324 result = dns_tsigkey_create(tkeyname, &rtkey.algorithm, r.base, 1325 r.length, true, NULL, rtkey.inception, 1326 rtkey.expire, rmsg->mctx, ring, outkey); 1327 isc_buffer_free(&shared); 1328 dns_rdata_freestruct(&rtkey); 1329 dst_key_free(&theirkey); 1330 return (result); 1331 1332 failure: 1333 if (shared != NULL) { 1334 isc_buffer_free(&shared); 1335 } 1336 1337 if (theirkey != NULL) { 1338 dst_key_free(&theirkey); 1339 } 1340 1341 if (freertkey) { 1342 dns_rdata_freestruct(&rtkey); 1343 } 1344 1345 return (result); 1346 } 1347 1348 isc_result_t 1349 dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1350 const dns_name_t *gname, dns_gss_ctx_id_t *context, 1351 isc_buffer_t *outtoken, dns_tsigkey_t **outkey, 1352 dns_tsig_keyring_t *ring, char **err_message) { 1353 dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1354 dns_name_t *tkeyname; 1355 dns_rdata_tkey_t rtkey, qtkey; 1356 dst_key_t *dstkey = NULL; 1357 isc_buffer_t intoken; 1358 isc_result_t result; 1359 unsigned char array[TEMP_BUFFER_SZ]; 1360 1361 REQUIRE(outtoken != NULL); 1362 REQUIRE(qmsg != NULL); 1363 REQUIRE(rmsg != NULL); 1364 REQUIRE(gname != NULL); 1365 REQUIRE(ring != NULL); 1366 if (outkey != NULL) { 1367 REQUIRE(*outkey == NULL); 1368 } 1369 1370 if (rmsg->rcode != dns_rcode_noerror) { 1371 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1372 } 1373 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1374 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1375 1376 /* 1377 * Win2k puts the item in the ANSWER section, while the RFC 1378 * specifies it should be in the ADDITIONAL section. Check first 1379 * where it should be, and then where it may be. 1380 */ 1381 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1382 DNS_SECTION_ADDITIONAL); 1383 if (result == ISC_R_NOTFOUND) { 1384 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1385 DNS_SECTION_ANSWER); 1386 } 1387 if (result != ISC_R_SUCCESS) { 1388 goto failure; 1389 } 1390 1391 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1392 1393 if (rtkey.error != dns_rcode_noerror || 1394 rtkey.mode != DNS_TKEYMODE_GSSAPI || 1395 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) 1396 { 1397 tkey_log("dns_tkey_processgssresponse: tkey mode invalid " 1398 "or error set(2) %d", 1399 rtkey.error); 1400 dumpmessage(qmsg); 1401 dumpmessage(rmsg); 1402 result = DNS_R_INVALIDTKEY; 1403 goto failure; 1404 } 1405 1406 isc_buffer_init(outtoken, array, sizeof(array)); 1407 isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1408 RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context, 1409 ring->mctx, err_message)); 1410 1411 RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, &dstkey, 1412 NULL)); 1413 1414 RETERR(dns_tsigkey_createfromkey( 1415 tkeyname, DNS_TSIG_GSSAPI_NAME, dstkey, false, NULL, 1416 rtkey.inception, rtkey.expire, ring->mctx, ring, outkey)); 1417 dst_key_free(&dstkey); 1418 dns_rdata_freestruct(&rtkey); 1419 return (result); 1420 1421 failure: 1422 /* 1423 * XXXSRA This probably leaks memory from rtkey and qtkey. 1424 */ 1425 if (dstkey != NULL) { 1426 dst_key_free(&dstkey); 1427 } 1428 return (result); 1429 } 1430 1431 isc_result_t 1432 dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1433 dns_tsig_keyring_t *ring) { 1434 dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1435 dns_name_t *tkeyname, *tempname; 1436 dns_rdata_tkey_t qtkey, rtkey; 1437 dns_tsigkey_t *tsigkey = NULL; 1438 isc_result_t result; 1439 1440 REQUIRE(qmsg != NULL); 1441 REQUIRE(rmsg != NULL); 1442 1443 if (rmsg->rcode != dns_rcode_noerror) { 1444 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1445 } 1446 1447 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1448 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1449 1450 RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, DNS_SECTION_ADDITIONAL)); 1451 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1452 1453 if (rtkey.error != dns_rcode_noerror || 1454 rtkey.mode != DNS_TKEYMODE_DELETE || rtkey.mode != qtkey.mode || 1455 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1456 rmsg->rcode != dns_rcode_noerror) 1457 { 1458 tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid " 1459 "or error set(3)"); 1460 result = DNS_R_INVALIDTKEY; 1461 dns_rdata_freestruct(&qtkey); 1462 dns_rdata_freestruct(&rtkey); 1463 goto failure; 1464 } 1465 1466 dns_rdata_freestruct(&qtkey); 1467 1468 RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm, ring)); 1469 1470 dns_rdata_freestruct(&rtkey); 1471 1472 /* 1473 * Mark the key as deleted. 1474 */ 1475 dns_tsigkey_setdeleted(tsigkey); 1476 /* 1477 * Release the reference. 1478 */ 1479 dns_tsigkey_detach(&tsigkey); 1480 1481 failure: 1482 return (result); 1483 } 1484 1485 isc_result_t 1486 dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, 1487 const dns_name_t *server, dns_gss_ctx_id_t *context, 1488 dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, 1489 bool win2k, char **err_message) { 1490 dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1491 dns_name_t *tkeyname; 1492 dns_rdata_tkey_t rtkey, qtkey, tkey; 1493 isc_buffer_t intoken, outtoken; 1494 dst_key_t *dstkey = NULL; 1495 isc_result_t result; 1496 unsigned char array[TEMP_BUFFER_SZ]; 1497 bool freertkey = false; 1498 1499 REQUIRE(qmsg != NULL); 1500 REQUIRE(rmsg != NULL); 1501 REQUIRE(server != NULL); 1502 if (outkey != NULL) { 1503 REQUIRE(*outkey == NULL); 1504 } 1505 1506 if (rmsg->rcode != dns_rcode_noerror) { 1507 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1508 } 1509 1510 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1511 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1512 freertkey = true; 1513 1514 if (win2k) { 1515 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1516 DNS_SECTION_ANSWER)); 1517 } else { 1518 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1519 DNS_SECTION_ADDITIONAL)); 1520 } 1521 1522 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1523 1524 if (rtkey.error != dns_rcode_noerror || 1525 rtkey.mode != DNS_TKEYMODE_GSSAPI || 1526 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) 1527 { 1528 tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1529 "or error set(4)"); 1530 result = DNS_R_INVALIDTKEY; 1531 goto failure; 1532 } 1533 1534 isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1535 isc_buffer_init(&outtoken, array, sizeof(array)); 1536 1537 result = dst_gssapi_initctx(server, &intoken, &outtoken, context, 1538 ring->mctx, err_message); 1539 if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) { 1540 return (result); 1541 } 1542 1543 if (result == DNS_R_CONTINUE) { 1544 dns_fixedname_t fixed; 1545 1546 dns_fixedname_init(&fixed); 1547 dns_name_copynf(tkeyname, dns_fixedname_name(&fixed)); 1548 tkeyname = dns_fixedname_name(&fixed); 1549 1550 tkey.common.rdclass = dns_rdataclass_any; 1551 tkey.common.rdtype = dns_rdatatype_tkey; 1552 ISC_LINK_INIT(&tkey.common, link); 1553 tkey.mctx = NULL; 1554 dns_name_init(&tkey.algorithm, NULL); 1555 1556 if (win2k) { 1557 dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); 1558 } else { 1559 dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); 1560 } 1561 1562 tkey.inception = qtkey.inception; 1563 tkey.expire = qtkey.expire; 1564 tkey.mode = DNS_TKEYMODE_GSSAPI; 1565 tkey.error = 0; 1566 tkey.key = isc_buffer_base(&outtoken); 1567 tkey.keylen = isc_buffer_usedlength(&outtoken); 1568 tkey.other = NULL; 1569 tkey.otherlen = 0; 1570 1571 dns_message_reset(qmsg, DNS_MESSAGE_INTENTRENDER); 1572 RETERR(buildquery(qmsg, tkeyname, &tkey, win2k)); 1573 return (DNS_R_CONTINUE); 1574 } 1575 1576 RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, &dstkey, 1577 NULL)); 1578 1579 /* 1580 * XXXSRA This seems confused. If we got CONTINUE from initctx, 1581 * the GSS negotiation hasn't completed yet, so we can't sign 1582 * anything yet. 1583 */ 1584 1585 RETERR(dns_tsigkey_createfromkey( 1586 tkeyname, 1587 (win2k ? DNS_TSIG_GSSAPIMS_NAME : DNS_TSIG_GSSAPI_NAME), dstkey, 1588 true, NULL, rtkey.inception, rtkey.expire, ring->mctx, ring, 1589 outkey)); 1590 dst_key_free(&dstkey); 1591 dns_rdata_freestruct(&rtkey); 1592 return (result); 1593 1594 failure: 1595 /* 1596 * XXXSRA This probably leaks memory from qtkey. 1597 */ 1598 if (freertkey) { 1599 dns_rdata_freestruct(&rtkey); 1600 } 1601 if (dstkey != NULL) { 1602 dst_key_free(&dstkey); 1603 } 1604 return (result); 1605 } 1606