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