1/* $NetBSD: tkey.c,v 1.1 2024/02/18 20:57:34 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 65static void 66tkey_log(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2); 67 68static void 69tkey_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 78static void 79dumpmessage(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 112isc_result_t 113dns_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 131void 132dns_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 160static isc_result_t 161add_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 199failure: 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 220static void 221free_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 240static isc_result_t 241compute_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; 342end: 343 if (md != NULL) { 344 isc_md_free(md); 345 } 346 return (result); 347} 348 349static isc_result_t 350process_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 488failure: 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 504static isc_result_t 505process_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 643failure: 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 662static isc_result_t 663process_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 699isc_result_t 700dns_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 { 779 signer = NULL; 780 } else { 781 tkey_log("dns_tkey_processquery: query was not " 782 "properly signed - rejecting"); 783 result = DNS_R_FORMERR; 784 goto failure; 785 } 786 } else { 787 signer = &tsigner; 788 } 789 790 tkeyout.common.rdclass = tkeyin.common.rdclass; 791 tkeyout.common.rdtype = tkeyin.common.rdtype; 792 ISC_LINK_INIT(&tkeyout.common, link); 793 tkeyout.mctx = msg->mctx; 794 795 dns_name_init(&tkeyout.algorithm, NULL); 796 dns_name_clone(&tkeyin.algorithm, &tkeyout.algorithm); 797 798 tkeyout.inception = tkeyout.expire = 0; 799 tkeyout.mode = tkeyin.mode; 800 tkeyout.error = 0; 801 tkeyout.keylen = tkeyout.otherlen = 0; 802 tkeyout.key = tkeyout.other = NULL; 803 804 /* 805 * A delete operation must have a fully specified key name. If this 806 * is not a delete, we do the following: 807 * if (qname != ".") 808 * keyname = qname + defaultdomain 809 * else 810 * keyname = <random hex> + defaultdomain 811 */ 812 if (tkeyin.mode != DNS_TKEYMODE_DELETE) { 813 dns_tsigkey_t *tsigkey = NULL; 814 815 if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) 816 { 817 tkey_log("dns_tkey_processquery: tkey-domain not set"); 818 result = DNS_R_REFUSED; 819 goto failure; 820 } 821 822 keyname = dns_fixedname_initname(&fkeyname); 823 824 if (!dns_name_equal(qname, dns_rootname)) { 825 unsigned int n = dns_name_countlabels(qname); 826 dns_name_copynf(qname, keyname); 827 dns_name_getlabelsequence(keyname, 0, n - 1, keyname); 828 } else { 829 static char hexdigits[16] = { '0', '1', '2', '3', 830 '4', '5', '6', '7', 831 '8', '9', 'A', 'B', 832 'C', 'D', 'E', 'F' }; 833 unsigned char randomdata[16]; 834 char randomtext[32]; 835 isc_buffer_t b; 836 unsigned int i, j; 837 838 isc_nonce_buf(randomdata, sizeof(randomdata)); 839 840 for (i = 0, j = 0; i < sizeof(randomdata); i++) { 841 unsigned char val = randomdata[i]; 842 randomtext[j++] = hexdigits[val >> 4]; 843 randomtext[j++] = hexdigits[val & 0xF]; 844 } 845 isc_buffer_init(&b, randomtext, sizeof(randomtext)); 846 isc_buffer_add(&b, sizeof(randomtext)); 847 result = dns_name_fromtext(keyname, &b, NULL, 0, NULL); 848 if (result != ISC_R_SUCCESS) { 849 goto failure; 850 } 851 } 852 853 if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) { 854 /* Yup. This is a hack */ 855 result = dns_name_concatenate(keyname, dns_rootname, 856 keyname, NULL); 857 if (result != ISC_R_SUCCESS) { 858 goto failure; 859 } 860 } else { 861 result = dns_name_concatenate(keyname, tctx->domain, 862 keyname, NULL); 863 if (result != ISC_R_SUCCESS) { 864 goto failure; 865 } 866 } 867 868 result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring); 869 870 if (result == ISC_R_SUCCESS) { 871 tkeyout.error = dns_tsigerror_badname; 872 dns_tsigkey_detach(&tsigkey); 873 goto failure_with_tkey; 874 } else if (result != ISC_R_NOTFOUND) { 875 goto failure; 876 } 877 } else { 878 keyname = qname; 879 } 880 881 switch (tkeyin.mode) { 882 case DNS_TKEYMODE_DIFFIEHELLMAN: 883 tkeyout.error = dns_rcode_noerror; 884 RETERR(process_dhtkey(msg, signer, keyname, &tkeyin, tctx, 885 &tkeyout, ring, &namelist)); 886 break; 887 case DNS_TKEYMODE_GSSAPI: 888 tkeyout.error = dns_rcode_noerror; 889 RETERR(process_gsstkey(msg, keyname, &tkeyin, tctx, &tkeyout, 890 ring)); 891 break; 892 case DNS_TKEYMODE_DELETE: 893 tkeyout.error = dns_rcode_noerror; 894 RETERR(process_deletetkey(signer, keyname, &tkeyin, &tkeyout, 895 ring)); 896 break; 897 case DNS_TKEYMODE_SERVERASSIGNED: 898 case DNS_TKEYMODE_RESOLVERASSIGNED: 899 result = DNS_R_NOTIMP; 900 goto failure; 901 default: 902 tkeyout.error = dns_tsigerror_badmode; 903 } 904 905failure_with_tkey: 906 907 dns_rdata_init(&rdata); 908 isc_buffer_init(&tkeyoutbuf, tkeyoutdata, sizeof(tkeyoutdata)); 909 result = dns_rdata_fromstruct(&rdata, tkeyout.common.rdclass, 910 tkeyout.common.rdtype, &tkeyout, 911 &tkeyoutbuf); 912 913 if (freetkeyin) { 914 dns_rdata_freestruct(&tkeyin); 915 freetkeyin = false; 916 } 917 918 if (tkeyout.key != NULL) { 919 isc_mem_put(tkeyout.mctx, tkeyout.key, tkeyout.keylen); 920 } 921 if (tkeyout.other != NULL) { 922 isc_mem_put(tkeyout.mctx, tkeyout.other, tkeyout.otherlen); 923 } 924 if (result != ISC_R_SUCCESS) { 925 goto failure; 926 } 927 928 RETERR(add_rdata_to_list(msg, keyname, &rdata, 0, &namelist)); 929 930 RETERR(dns_message_reply(msg, true)); 931 932 name = ISC_LIST_HEAD(namelist); 933 while (name != NULL) { 934 dns_name_t *next = ISC_LIST_NEXT(name, link); 935 ISC_LIST_UNLINK(namelist, name, link); 936 dns_message_addname(msg, name, DNS_SECTION_ANSWER); 937 name = next; 938 } 939 940 return (ISC_R_SUCCESS); 941 942failure: 943 944 if (freetkeyin) { 945 dns_rdata_freestruct(&tkeyin); 946 } 947 if (!ISC_LIST_EMPTY(namelist)) { 948 free_namelist(msg, &namelist); 949 } 950 return (result); 951} 952 953static isc_result_t 954buildquery(dns_message_t *msg, const dns_name_t *name, dns_rdata_tkey_t *tkey, 955 bool win2k) { 956 dns_name_t *qname = NULL, *aname = NULL; 957 dns_rdataset_t *question = NULL, *tkeyset = NULL; 958 dns_rdatalist_t *tkeylist = NULL; 959 dns_rdata_t *rdata = NULL; 960 isc_buffer_t *dynbuf = NULL; 961 isc_result_t result; 962 unsigned int len; 963 964 REQUIRE(msg != NULL); 965 REQUIRE(name != NULL); 966 REQUIRE(tkey != NULL); 967 968 RETERR(dns_message_gettempname(msg, &qname)); 969 RETERR(dns_message_gettempname(msg, &aname)); 970 971 RETERR(dns_message_gettemprdataset(msg, &question)); 972 dns_rdataset_makequestion(question, dns_rdataclass_any, 973 dns_rdatatype_tkey); 974 975 len = 16 + tkey->algorithm.length + tkey->keylen + tkey->otherlen; 976 isc_buffer_allocate(msg->mctx, &dynbuf, len); 977 RETERR(dns_message_gettemprdata(msg, &rdata)); 978 979 RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any, 980 dns_rdatatype_tkey, tkey, dynbuf)); 981 dns_message_takebuffer(msg, &dynbuf); 982 983 RETERR(dns_message_gettemprdatalist(msg, &tkeylist)); 984 tkeylist->rdclass = dns_rdataclass_any; 985 tkeylist->type = dns_rdatatype_tkey; 986 ISC_LIST_APPEND(tkeylist->rdata, rdata, link); 987 988 RETERR(dns_message_gettemprdataset(msg, &tkeyset)); 989 RETERR(dns_rdatalist_tordataset(tkeylist, tkeyset)); 990 991 dns_name_copynf(name, qname); 992 dns_name_copynf(name, aname); 993 994 ISC_LIST_APPEND(qname->list, question, link); 995 ISC_LIST_APPEND(aname->list, tkeyset, link); 996 997 dns_message_addname(msg, qname, DNS_SECTION_QUESTION); 998 999 /* 1000 * Windows 2000 needs this in the answer section, not the additional 1001 * section where the RFC specifies. 1002 */ 1003 if (win2k) { 1004 dns_message_addname(msg, aname, DNS_SECTION_ANSWER); 1005 } else { 1006 dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL); 1007 } 1008 1009 return (ISC_R_SUCCESS); 1010 1011failure: 1012 if (qname != NULL) { 1013 dns_message_puttempname(msg, &qname); 1014 } 1015 if (aname != NULL) { 1016 dns_message_puttempname(msg, &aname); 1017 } 1018 if (question != NULL) { 1019 dns_rdataset_disassociate(question); 1020 dns_message_puttemprdataset(msg, &question); 1021 } 1022 if (dynbuf != NULL) { 1023 isc_buffer_free(&dynbuf); 1024 } 1025 if (rdata != NULL) { 1026 dns_message_puttemprdata(msg, &rdata); 1027 } 1028 if (tkeylist != NULL) { 1029 dns_message_puttemprdatalist(msg, &tkeylist); 1030 } 1031 if (tkeyset != NULL) { 1032 if (dns_rdataset_isassociated(tkeyset)) { 1033 dns_rdataset_disassociate(tkeyset); 1034 } 1035 dns_message_puttemprdataset(msg, &tkeyset); 1036 } 1037 return (result); 1038} 1039 1040isc_result_t 1041dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, 1042 const dns_name_t *name, const dns_name_t *algorithm, 1043 isc_buffer_t *nonce, uint32_t lifetime) { 1044 dns_rdata_tkey_t tkey; 1045 dns_rdata_t *rdata = NULL; 1046 isc_buffer_t *dynbuf = NULL; 1047 isc_region_t r; 1048 dns_name_t keyname; 1049 dns_namelist_t namelist; 1050 isc_result_t result; 1051 isc_stdtime_t now; 1052 dns_name_t *item; 1053 1054 REQUIRE(msg != NULL); 1055 REQUIRE(key != NULL); 1056 REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 1057 REQUIRE(dst_key_isprivate(key)); 1058 REQUIRE(name != NULL); 1059 REQUIRE(algorithm != NULL); 1060 1061 tkey.common.rdclass = dns_rdataclass_any; 1062 tkey.common.rdtype = dns_rdatatype_tkey; 1063 ISC_LINK_INIT(&tkey.common, link); 1064 tkey.mctx = msg->mctx; 1065 dns_name_init(&tkey.algorithm, NULL); 1066 dns_name_clone(algorithm, &tkey.algorithm); 1067 isc_stdtime_get(&now); 1068 tkey.inception = now; 1069 tkey.expire = now + lifetime; 1070 tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN; 1071 if (nonce != NULL) { 1072 isc_buffer_usedregion(nonce, &r); 1073 } else { 1074 r.base = NULL; 1075 r.length = 0; 1076 } 1077 tkey.error = 0; 1078 tkey.key = r.base; 1079 tkey.keylen = r.length; 1080 tkey.other = NULL; 1081 tkey.otherlen = 0; 1082 1083 RETERR(buildquery(msg, name, &tkey, false)); 1084 1085 RETERR(dns_message_gettemprdata(msg, &rdata)); 1086 isc_buffer_allocate(msg->mctx, &dynbuf, 1024); 1087 RETERR(dst_key_todns(key, dynbuf)); 1088 isc_buffer_usedregion(dynbuf, &r); 1089 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_key, &r); 1090 dns_message_takebuffer(msg, &dynbuf); 1091 1092 dns_name_init(&keyname, NULL); 1093 dns_name_clone(dst_key_name(key), &keyname); 1094 1095 ISC_LIST_INIT(namelist); 1096 RETERR(add_rdata_to_list(msg, &keyname, rdata, 0, &namelist)); 1097 item = ISC_LIST_HEAD(namelist); 1098 while (item != NULL) { 1099 dns_name_t *next = ISC_LIST_NEXT(item, link); 1100 ISC_LIST_UNLINK(namelist, item, link); 1101 dns_message_addname(msg, item, DNS_SECTION_ADDITIONAL); 1102 item = next; 1103 } 1104 1105 return (ISC_R_SUCCESS); 1106 1107failure: 1108 1109 if (dynbuf != NULL) { 1110 isc_buffer_free(&dynbuf); 1111 } 1112 return (result); 1113} 1114 1115isc_result_t 1116dns_tkey_buildgssquery(dns_message_t *msg, const dns_name_t *name, 1117 const dns_name_t *gname, isc_buffer_t *intoken, 1118 uint32_t lifetime, dns_gss_ctx_id_t *context, bool win2k, 1119 isc_mem_t *mctx, char **err_message) { 1120 dns_rdata_tkey_t tkey; 1121 isc_result_t result; 1122 isc_stdtime_t now; 1123 isc_buffer_t token; 1124 unsigned char array[TEMP_BUFFER_SZ]; 1125 1126 UNUSED(intoken); 1127 1128 REQUIRE(msg != NULL); 1129 REQUIRE(name != NULL); 1130 REQUIRE(gname != NULL); 1131 REQUIRE(context != NULL); 1132 REQUIRE(mctx != NULL); 1133 1134 isc_buffer_init(&token, array, sizeof(array)); 1135 result = dst_gssapi_initctx(gname, NULL, &token, context, mctx, 1136 err_message); 1137 if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) { 1138 return (result); 1139 } 1140 1141 tkey.common.rdclass = dns_rdataclass_any; 1142 tkey.common.rdtype = dns_rdatatype_tkey; 1143 ISC_LINK_INIT(&tkey.common, link); 1144 tkey.mctx = NULL; 1145 dns_name_init(&tkey.algorithm, NULL); 1146 1147 if (win2k) { 1148 dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); 1149 } else { 1150 dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); 1151 } 1152 1153 isc_stdtime_get(&now); 1154 tkey.inception = now; 1155 tkey.expire = now + lifetime; 1156 tkey.mode = DNS_TKEYMODE_GSSAPI; 1157 tkey.error = 0; 1158 tkey.key = isc_buffer_base(&token); 1159 tkey.keylen = isc_buffer_usedlength(&token); 1160 tkey.other = NULL; 1161 tkey.otherlen = 0; 1162 1163 return (buildquery(msg, name, &tkey, win2k)); 1164} 1165 1166isc_result_t 1167dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) { 1168 dns_rdata_tkey_t tkey; 1169 1170 REQUIRE(msg != NULL); 1171 REQUIRE(key != NULL); 1172 1173 tkey.common.rdclass = dns_rdataclass_any; 1174 tkey.common.rdtype = dns_rdatatype_tkey; 1175 ISC_LINK_INIT(&tkey.common, link); 1176 tkey.mctx = msg->mctx; 1177 dns_name_init(&tkey.algorithm, NULL); 1178 dns_name_clone(key->algorithm, &tkey.algorithm); 1179 tkey.inception = tkey.expire = 0; 1180 tkey.mode = DNS_TKEYMODE_DELETE; 1181 tkey.error = 0; 1182 tkey.keylen = tkey.otherlen = 0; 1183 tkey.key = tkey.other = NULL; 1184 1185 return (buildquery(msg, &key->name, &tkey, false)); 1186} 1187 1188static isc_result_t 1189find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata, 1190 int section) { 1191 dns_rdataset_t *tkeyset; 1192 isc_result_t result; 1193 1194 result = dns_message_firstname(msg, section); 1195 while (result == ISC_R_SUCCESS) { 1196 *name = NULL; 1197 dns_message_currentname(msg, section, name); 1198 tkeyset = NULL; 1199 result = dns_message_findtype(*name, dns_rdatatype_tkey, 0, 1200 &tkeyset); 1201 if (result == ISC_R_SUCCESS) { 1202 result = dns_rdataset_first(tkeyset); 1203 if (result != ISC_R_SUCCESS) { 1204 return (result); 1205 } 1206 dns_rdataset_current(tkeyset, rdata); 1207 return (ISC_R_SUCCESS); 1208 } 1209 result = dns_message_nextname(msg, section); 1210 } 1211 if (result == ISC_R_NOMORE) { 1212 return (ISC_R_NOTFOUND); 1213 } 1214 return (result); 1215} 1216 1217isc_result_t 1218dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1219 dst_key_t *key, isc_buffer_t *nonce, 1220 dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring) { 1221 dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1222 dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname; 1223 dns_rdataset_t *theirkeyset = NULL, *ourkeyset = NULL; 1224 dns_rdata_t theirkeyrdata = DNS_RDATA_INIT; 1225 dst_key_t *theirkey = NULL; 1226 dns_rdata_tkey_t qtkey, rtkey; 1227 unsigned char secretdata[256]; 1228 unsigned int sharedsize; 1229 isc_buffer_t *shared = NULL, secret; 1230 isc_region_t r, r2; 1231 isc_result_t result; 1232 bool freertkey = false; 1233 1234 REQUIRE(qmsg != NULL); 1235 REQUIRE(rmsg != NULL); 1236 REQUIRE(key != NULL); 1237 REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 1238 REQUIRE(dst_key_isprivate(key)); 1239 if (outkey != NULL) { 1240 REQUIRE(*outkey == NULL); 1241 } 1242 1243 if (rmsg->rcode != dns_rcode_noerror) { 1244 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1245 } 1246 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1247 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1248 freertkey = true; 1249 1250 RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, DNS_SECTION_ADDITIONAL)); 1251 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1252 1253 if (rtkey.error != dns_rcode_noerror || 1254 rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN || 1255 rtkey.mode != qtkey.mode || 1256 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1257 rmsg->rcode != dns_rcode_noerror) 1258 { 1259 tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1260 "or error set(1)"); 1261 result = DNS_R_INVALIDTKEY; 1262 dns_rdata_freestruct(&qtkey); 1263 goto failure; 1264 } 1265 1266 dns_rdata_freestruct(&qtkey); 1267 1268 dns_name_init(&keyname, NULL); 1269 dns_name_clone(dst_key_name(key), &keyname); 1270 1271 ourkeyname = NULL; 1272 ourkeyset = NULL; 1273 RETERR(dns_message_findname(rmsg, DNS_SECTION_ANSWER, &keyname, 1274 dns_rdatatype_key, 0, &ourkeyname, 1275 &ourkeyset)); 1276 1277 result = dns_message_firstname(rmsg, DNS_SECTION_ANSWER); 1278 while (result == ISC_R_SUCCESS) { 1279 theirkeyname = NULL; 1280 dns_message_currentname(rmsg, DNS_SECTION_ANSWER, 1281 &theirkeyname); 1282 if (dns_name_equal(theirkeyname, ourkeyname)) { 1283 goto next; 1284 } 1285 theirkeyset = NULL; 1286 result = dns_message_findtype(theirkeyname, dns_rdatatype_key, 1287 0, &theirkeyset); 1288 if (result == ISC_R_SUCCESS) { 1289 RETERR(dns_rdataset_first(theirkeyset)); 1290 break; 1291 } 1292 next: 1293 result = dns_message_nextname(rmsg, DNS_SECTION_ANSWER); 1294 } 1295 1296 if (theirkeyset == NULL) { 1297 tkey_log("dns_tkey_processdhresponse: failed to find server " 1298 "key"); 1299 result = ISC_R_NOTFOUND; 1300 goto failure; 1301 } 1302 1303 dns_rdataset_current(theirkeyset, &theirkeyrdata); 1304 RETERR(dns_dnssec_keyfromrdata(theirkeyname, &theirkeyrdata, rmsg->mctx, 1305 &theirkey)); 1306 1307 RETERR(dst_key_secretsize(key, &sharedsize)); 1308 isc_buffer_allocate(rmsg->mctx, &shared, sharedsize); 1309 1310 RETERR(dst_key_computesecret(theirkey, key, shared)); 1311 1312 isc_buffer_init(&secret, secretdata, sizeof(secretdata)); 1313 1314 r.base = rtkey.key; 1315 r.length = rtkey.keylen; 1316 if (nonce != NULL) { 1317 isc_buffer_usedregion(nonce, &r2); 1318 } else { 1319 r2.base = NULL; 1320 r2.length = 0; 1321 } 1322 RETERR(compute_secret(shared, &r2, &r, &secret)); 1323 1324 isc_buffer_usedregion(&secret, &r); 1325 result = dns_tsigkey_create(tkeyname, &rtkey.algorithm, r.base, 1326 r.length, true, NULL, rtkey.inception, 1327 rtkey.expire, rmsg->mctx, ring, outkey); 1328 isc_buffer_free(&shared); 1329 dns_rdata_freestruct(&rtkey); 1330 dst_key_free(&theirkey); 1331 return (result); 1332 1333failure: 1334 if (shared != NULL) { 1335 isc_buffer_free(&shared); 1336 } 1337 1338 if (theirkey != NULL) { 1339 dst_key_free(&theirkey); 1340 } 1341 1342 if (freertkey) { 1343 dns_rdata_freestruct(&rtkey); 1344 } 1345 1346 return (result); 1347} 1348 1349isc_result_t 1350dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1351 const dns_name_t *gname, dns_gss_ctx_id_t *context, 1352 isc_buffer_t *outtoken, dns_tsigkey_t **outkey, 1353 dns_tsig_keyring_t *ring, char **err_message) { 1354 dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1355 dns_name_t *tkeyname; 1356 dns_rdata_tkey_t rtkey, qtkey; 1357 dst_key_t *dstkey = NULL; 1358 isc_buffer_t intoken; 1359 isc_result_t result; 1360 unsigned char array[TEMP_BUFFER_SZ]; 1361 1362 REQUIRE(outtoken != NULL); 1363 REQUIRE(qmsg != NULL); 1364 REQUIRE(rmsg != NULL); 1365 REQUIRE(gname != NULL); 1366 REQUIRE(ring != NULL); 1367 if (outkey != NULL) { 1368 REQUIRE(*outkey == NULL); 1369 } 1370 1371 if (rmsg->rcode != dns_rcode_noerror) { 1372 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1373 } 1374 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1375 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1376 1377 /* 1378 * Win2k puts the item in the ANSWER section, while the RFC 1379 * specifies it should be in the ADDITIONAL section. Check first 1380 * where it should be, and then where it may be. 1381 */ 1382 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1383 DNS_SECTION_ADDITIONAL); 1384 if (result == ISC_R_NOTFOUND) { 1385 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1386 DNS_SECTION_ANSWER); 1387 } 1388 if (result != ISC_R_SUCCESS) { 1389 goto failure; 1390 } 1391 1392 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1393 1394 if (rtkey.error != dns_rcode_noerror || 1395 rtkey.mode != DNS_TKEYMODE_GSSAPI || 1396 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) 1397 { 1398 tkey_log("dns_tkey_processgssresponse: tkey mode invalid " 1399 "or error set(2) %d", 1400 rtkey.error); 1401 dumpmessage(qmsg); 1402 dumpmessage(rmsg); 1403 result = DNS_R_INVALIDTKEY; 1404 goto failure; 1405 } 1406 1407 isc_buffer_init(outtoken, array, sizeof(array)); 1408 isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1409 RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context, 1410 ring->mctx, err_message)); 1411 1412 RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, &dstkey, 1413 NULL)); 1414 1415 RETERR(dns_tsigkey_createfromkey( 1416 tkeyname, DNS_TSIG_GSSAPI_NAME, dstkey, false, NULL, 1417 rtkey.inception, rtkey.expire, ring->mctx, ring, outkey)); 1418 dst_key_free(&dstkey); 1419 dns_rdata_freestruct(&rtkey); 1420 return (result); 1421 1422failure: 1423 /* 1424 * XXXSRA This probably leaks memory from rtkey and qtkey. 1425 */ 1426 if (dstkey != NULL) { 1427 dst_key_free(&dstkey); 1428 } 1429 return (result); 1430} 1431 1432isc_result_t 1433dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1434 dns_tsig_keyring_t *ring) { 1435 dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1436 dns_name_t *tkeyname, *tempname; 1437 dns_rdata_tkey_t qtkey, rtkey; 1438 dns_tsigkey_t *tsigkey = NULL; 1439 isc_result_t result; 1440 1441 REQUIRE(qmsg != NULL); 1442 REQUIRE(rmsg != NULL); 1443 1444 if (rmsg->rcode != dns_rcode_noerror) { 1445 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1446 } 1447 1448 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1449 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1450 1451 RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, DNS_SECTION_ADDITIONAL)); 1452 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1453 1454 if (rtkey.error != dns_rcode_noerror || 1455 rtkey.mode != DNS_TKEYMODE_DELETE || rtkey.mode != qtkey.mode || 1456 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1457 rmsg->rcode != dns_rcode_noerror) 1458 { 1459 tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid " 1460 "or error set(3)"); 1461 result = DNS_R_INVALIDTKEY; 1462 dns_rdata_freestruct(&qtkey); 1463 dns_rdata_freestruct(&rtkey); 1464 goto failure; 1465 } 1466 1467 dns_rdata_freestruct(&qtkey); 1468 1469 RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm, ring)); 1470 1471 dns_rdata_freestruct(&rtkey); 1472 1473 /* 1474 * Mark the key as deleted. 1475 */ 1476 dns_tsigkey_setdeleted(tsigkey); 1477 /* 1478 * Release the reference. 1479 */ 1480 dns_tsigkey_detach(&tsigkey); 1481 1482failure: 1483 return (result); 1484} 1485 1486isc_result_t 1487dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, 1488 const dns_name_t *server, dns_gss_ctx_id_t *context, 1489 dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, 1490 bool win2k, char **err_message) { 1491 dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1492 dns_name_t *tkeyname; 1493 dns_rdata_tkey_t rtkey, qtkey, tkey; 1494 isc_buffer_t intoken, outtoken; 1495 dst_key_t *dstkey = NULL; 1496 isc_result_t result; 1497 unsigned char array[TEMP_BUFFER_SZ]; 1498 bool freertkey = false; 1499 1500 REQUIRE(qmsg != NULL); 1501 REQUIRE(rmsg != NULL); 1502 REQUIRE(server != NULL); 1503 if (outkey != NULL) { 1504 REQUIRE(*outkey == NULL); 1505 } 1506 1507 if (rmsg->rcode != dns_rcode_noerror) { 1508 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1509 } 1510 1511 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1512 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1513 freertkey = true; 1514 1515 if (win2k) { 1516 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1517 DNS_SECTION_ANSWER)); 1518 } else { 1519 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1520 DNS_SECTION_ADDITIONAL)); 1521 } 1522 1523 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1524 1525 if (rtkey.error != dns_rcode_noerror || 1526 rtkey.mode != DNS_TKEYMODE_GSSAPI || 1527 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) 1528 { 1529 tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1530 "or error set(4)"); 1531 result = DNS_R_INVALIDTKEY; 1532 goto failure; 1533 } 1534 1535 isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1536 isc_buffer_init(&outtoken, array, sizeof(array)); 1537 1538 result = dst_gssapi_initctx(server, &intoken, &outtoken, context, 1539 ring->mctx, err_message); 1540 if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) { 1541 return (result); 1542 } 1543 1544 if (result == DNS_R_CONTINUE) { 1545 dns_fixedname_t fixed; 1546 1547 dns_fixedname_init(&fixed); 1548 dns_name_copynf(tkeyname, dns_fixedname_name(&fixed)); 1549 tkeyname = dns_fixedname_name(&fixed); 1550 1551 tkey.common.rdclass = dns_rdataclass_any; 1552 tkey.common.rdtype = dns_rdatatype_tkey; 1553 ISC_LINK_INIT(&tkey.common, link); 1554 tkey.mctx = NULL; 1555 dns_name_init(&tkey.algorithm, NULL); 1556 1557 if (win2k) { 1558 dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); 1559 } else { 1560 dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); 1561 } 1562 1563 tkey.inception = qtkey.inception; 1564 tkey.expire = qtkey.expire; 1565 tkey.mode = DNS_TKEYMODE_GSSAPI; 1566 tkey.error = 0; 1567 tkey.key = isc_buffer_base(&outtoken); 1568 tkey.keylen = isc_buffer_usedlength(&outtoken); 1569 tkey.other = NULL; 1570 tkey.otherlen = 0; 1571 1572 dns_message_reset(qmsg, DNS_MESSAGE_INTENTRENDER); 1573 RETERR(buildquery(qmsg, tkeyname, &tkey, win2k)); 1574 return (DNS_R_CONTINUE); 1575 } 1576 1577 RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, &dstkey, 1578 NULL)); 1579 1580 /* 1581 * XXXSRA This seems confused. If we got CONTINUE from initctx, 1582 * the GSS negotiation hasn't completed yet, so we can't sign 1583 * anything yet. 1584 */ 1585 1586 RETERR(dns_tsigkey_createfromkey( 1587 tkeyname, 1588 (win2k ? DNS_TSIG_GSSAPIMS_NAME : DNS_TSIG_GSSAPI_NAME), dstkey, 1589 true, NULL, rtkey.inception, rtkey.expire, ring->mctx, ring, 1590 outkey)); 1591 dst_key_free(&dstkey); 1592 dns_rdata_freestruct(&rtkey); 1593 return (result); 1594 1595failure: 1596 /* 1597 * XXXSRA This probably leaks memory from qtkey. 1598 */ 1599 if (freertkey) { 1600 dns_rdata_freestruct(&rtkey); 1601 } 1602 if (dstkey != NULL) { 1603 dst_key_free(&dstkey); 1604 } 1605 return (result); 1606} 1607