tkey.c revision 285980
1/* 2 * Copyright (C) 2004-2014 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 memmove(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 memmove(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 memmove(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 memmove(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 memmove(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 name = NULL; 654 if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 655 dns_rdatatype_tkey, 0, &name, 656 &tkeyset) != ISC_R_SUCCESS) { 657 result = DNS_R_FORMERR; 658 tkey_log("dns_tkey_processquery: couldn't find a TKEY " 659 "matching the question"); 660 goto failure; 661 } 662 } 663 result = dns_rdataset_first(tkeyset); 664 if (result != ISC_R_SUCCESS) { 665 result = DNS_R_FORMERR; 666 goto failure; 667 } 668 dns_rdata_init(&rdata); 669 dns_rdataset_current(tkeyset, &rdata); 670 671 RETERR(dns_rdata_tostruct(&rdata, &tkeyin, NULL)); 672 freetkeyin = ISC_TRUE; 673 674 if (tkeyin.error != dns_rcode_noerror) { 675 result = DNS_R_FORMERR; 676 goto failure; 677 } 678 679 /* 680 * Before we go any farther, verify that the message was signed. 681 * GSSAPI TKEY doesn't require a signature, the rest do. 682 */ 683 dns_name_init(&tsigner, NULL); 684 result = dns_message_signer(msg, &tsigner); 685 if (result != ISC_R_SUCCESS) { 686 if (tkeyin.mode == DNS_TKEYMODE_GSSAPI && 687 result == ISC_R_NOTFOUND) 688 signer = NULL; 689 else { 690 tkey_log("dns_tkey_processquery: query was not " 691 "properly signed - rejecting"); 692 result = DNS_R_FORMERR; 693 goto failure; 694 } 695 } else 696 signer = &tsigner; 697 698 tkeyout.common.rdclass = tkeyin.common.rdclass; 699 tkeyout.common.rdtype = tkeyin.common.rdtype; 700 ISC_LINK_INIT(&tkeyout.common, link); 701 tkeyout.mctx = msg->mctx; 702 703 dns_name_init(&tkeyout.algorithm, NULL); 704 dns_name_clone(&tkeyin.algorithm, &tkeyout.algorithm); 705 706 tkeyout.inception = tkeyout.expire = 0; 707 tkeyout.mode = tkeyin.mode; 708 tkeyout.error = 0; 709 tkeyout.keylen = tkeyout.otherlen = 0; 710 tkeyout.key = tkeyout.other = NULL; 711 712 /* 713 * A delete operation must have a fully specified key name. If this 714 * is not a delete, we do the following: 715 * if (qname != ".") 716 * keyname = qname + defaultdomain 717 * else 718 * keyname = <random hex> + defaultdomain 719 */ 720 if (tkeyin.mode != DNS_TKEYMODE_DELETE) { 721 dns_tsigkey_t *tsigkey = NULL; 722 723 if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) { 724 tkey_log("dns_tkey_processquery: tkey-domain not set"); 725 result = DNS_R_REFUSED; 726 goto failure; 727 } 728 729 dns_fixedname_init(&fkeyname); 730 keyname = dns_fixedname_name(&fkeyname); 731 732 if (!dns_name_equal(qname, dns_rootname)) { 733 unsigned int n = dns_name_countlabels(qname); 734 RUNTIME_CHECK(dns_name_copy(qname, keyname, NULL) 735 == ISC_R_SUCCESS); 736 dns_name_getlabelsequence(keyname, 0, n - 1, keyname); 737 } else { 738 static char hexdigits[16] = { 739 '0', '1', '2', '3', '4', '5', '6', '7', 740 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 741 unsigned char randomdata[16]; 742 char randomtext[32]; 743 isc_buffer_t b; 744 unsigned int i, j; 745 746 result = isc_entropy_getdata(tctx->ectx, 747 randomdata, 748 sizeof(randomdata), 749 NULL, 0); 750 if (result != ISC_R_SUCCESS) 751 goto failure; 752 753 for (i = 0, j = 0; i < sizeof(randomdata); i++) { 754 unsigned char val = randomdata[i]; 755 randomtext[j++] = hexdigits[val >> 4]; 756 randomtext[j++] = hexdigits[val & 0xF]; 757 } 758 isc_buffer_init(&b, randomtext, sizeof(randomtext)); 759 isc_buffer_add(&b, sizeof(randomtext)); 760 result = dns_name_fromtext(keyname, &b, NULL, 0, NULL); 761 if (result != ISC_R_SUCCESS) 762 goto failure; 763 } 764 765 if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) { 766 /* Yup. This is a hack */ 767 result = dns_name_concatenate(keyname, dns_rootname, 768 keyname, NULL); 769 if (result != ISC_R_SUCCESS) 770 goto failure; 771 } else { 772 result = dns_name_concatenate(keyname, tctx->domain, 773 keyname, NULL); 774 if (result != ISC_R_SUCCESS) 775 goto failure; 776 } 777 778 result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring); 779 780 if (result == ISC_R_SUCCESS) { 781 tkeyout.error = dns_tsigerror_badname; 782 dns_tsigkey_detach(&tsigkey); 783 goto failure_with_tkey; 784 } else if (result != ISC_R_NOTFOUND) 785 goto failure; 786 } else 787 keyname = qname; 788 789 switch (tkeyin.mode) { 790 case DNS_TKEYMODE_DIFFIEHELLMAN: 791 tkeyout.error = dns_rcode_noerror; 792 RETERR(process_dhtkey(msg, signer, keyname, &tkeyin, 793 tctx, &tkeyout, ring, 794 &namelist)); 795 break; 796 case DNS_TKEYMODE_GSSAPI: 797 tkeyout.error = dns_rcode_noerror; 798 RETERR(process_gsstkey(keyname, &tkeyin, tctx, 799 &tkeyout, ring)); 800 break; 801 case DNS_TKEYMODE_DELETE: 802 tkeyout.error = dns_rcode_noerror; 803 RETERR(process_deletetkey(signer, keyname, &tkeyin, 804 &tkeyout, ring)); 805 break; 806 case DNS_TKEYMODE_SERVERASSIGNED: 807 case DNS_TKEYMODE_RESOLVERASSIGNED: 808 result = DNS_R_NOTIMP; 809 goto failure; 810 default: 811 tkeyout.error = dns_tsigerror_badmode; 812 } 813 814 failure_with_tkey: 815 dns_rdata_init(&rdata); 816 isc_buffer_init(&tkeyoutbuf, tkeyoutdata, sizeof(tkeyoutdata)); 817 result = dns_rdata_fromstruct(&rdata, tkeyout.common.rdclass, 818 tkeyout.common.rdtype, &tkeyout, 819 &tkeyoutbuf); 820 821 if (freetkeyin) { 822 dns_rdata_freestruct(&tkeyin); 823 freetkeyin = ISC_FALSE; 824 } 825 826 if (tkeyout.key != NULL) 827 isc_mem_put(tkeyout.mctx, tkeyout.key, tkeyout.keylen); 828 if (tkeyout.other != NULL) 829 isc_mem_put(tkeyout.mctx, tkeyout.other, tkeyout.otherlen); 830 if (result != ISC_R_SUCCESS) 831 goto failure; 832 833 RETERR(add_rdata_to_list(msg, keyname, &rdata, 0, &namelist)); 834 835 RETERR(dns_message_reply(msg, ISC_TRUE)); 836 837 name = ISC_LIST_HEAD(namelist); 838 while (name != NULL) { 839 dns_name_t *next = ISC_LIST_NEXT(name, link); 840 ISC_LIST_UNLINK(namelist, name, link); 841 dns_message_addname(msg, name, DNS_SECTION_ANSWER); 842 name = next; 843 } 844 845 return (ISC_R_SUCCESS); 846 847 failure: 848 if (freetkeyin) 849 dns_rdata_freestruct(&tkeyin); 850 if (!ISC_LIST_EMPTY(namelist)) 851 free_namelist(msg, &namelist); 852 return (result); 853} 854 855static isc_result_t 856buildquery(dns_message_t *msg, dns_name_t *name, 857 dns_rdata_tkey_t *tkey, isc_boolean_t win2k) 858{ 859 dns_name_t *qname = NULL, *aname = NULL; 860 dns_rdataset_t *question = NULL, *tkeyset = NULL; 861 dns_rdatalist_t *tkeylist = NULL; 862 dns_rdata_t *rdata = NULL; 863 isc_buffer_t *dynbuf = NULL; 864 isc_result_t result; 865 866 REQUIRE(msg != NULL); 867 REQUIRE(name != NULL); 868 REQUIRE(tkey != NULL); 869 870 RETERR(dns_message_gettempname(msg, &qname)); 871 RETERR(dns_message_gettempname(msg, &aname)); 872 873 RETERR(dns_message_gettemprdataset(msg, &question)); 874 dns_rdataset_init(question); 875 dns_rdataset_makequestion(question, dns_rdataclass_any, 876 dns_rdatatype_tkey); 877 878 RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 4096)); 879 RETERR(dns_message_gettemprdata(msg, &rdata)); 880 881 RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any, 882 dns_rdatatype_tkey, tkey, dynbuf)); 883 dns_message_takebuffer(msg, &dynbuf); 884 885 RETERR(dns_message_gettemprdatalist(msg, &tkeylist)); 886 tkeylist->rdclass = dns_rdataclass_any; 887 tkeylist->type = dns_rdatatype_tkey; 888 tkeylist->covers = 0; 889 tkeylist->ttl = 0; 890 ISC_LIST_INIT(tkeylist->rdata); 891 ISC_LIST_APPEND(tkeylist->rdata, rdata, link); 892 893 RETERR(dns_message_gettemprdataset(msg, &tkeyset)); 894 dns_rdataset_init(tkeyset); 895 RETERR(dns_rdatalist_tordataset(tkeylist, tkeyset)); 896 897 dns_name_init(qname, NULL); 898 dns_name_clone(name, qname); 899 900 dns_name_init(aname, NULL); 901 dns_name_clone(name, aname); 902 903 ISC_LIST_APPEND(qname->list, question, link); 904 ISC_LIST_APPEND(aname->list, tkeyset, link); 905 906 dns_message_addname(msg, qname, DNS_SECTION_QUESTION); 907 908 /* 909 * Windows 2000 needs this in the answer section, not the additional 910 * section where the RFC specifies. 911 */ 912 if (win2k) 913 dns_message_addname(msg, aname, DNS_SECTION_ANSWER); 914 else 915 dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL); 916 917 return (ISC_R_SUCCESS); 918 919 failure: 920 if (qname != NULL) 921 dns_message_puttempname(msg, &qname); 922 if (aname != NULL) 923 dns_message_puttempname(msg, &aname); 924 if (question != NULL) { 925 dns_rdataset_disassociate(question); 926 dns_message_puttemprdataset(msg, &question); 927 } 928 if (dynbuf != NULL) 929 isc_buffer_free(&dynbuf); 930 printf("buildquery error\n"); 931 return (result); 932} 933 934isc_result_t 935dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, 936 dns_name_t *algorithm, isc_buffer_t *nonce, 937 isc_uint32_t lifetime) 938{ 939 dns_rdata_tkey_t tkey; 940 dns_rdata_t *rdata = NULL; 941 isc_buffer_t *dynbuf = NULL; 942 isc_region_t r; 943 dns_name_t keyname; 944 dns_namelist_t namelist; 945 isc_result_t result; 946 isc_stdtime_t now; 947 948 REQUIRE(msg != NULL); 949 REQUIRE(key != NULL); 950 REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 951 REQUIRE(dst_key_isprivate(key)); 952 REQUIRE(name != NULL); 953 REQUIRE(algorithm != NULL); 954 955 tkey.common.rdclass = dns_rdataclass_any; 956 tkey.common.rdtype = dns_rdatatype_tkey; 957 ISC_LINK_INIT(&tkey.common, link); 958 tkey.mctx = msg->mctx; 959 dns_name_init(&tkey.algorithm, NULL); 960 dns_name_clone(algorithm, &tkey.algorithm); 961 isc_stdtime_get(&now); 962 tkey.inception = now; 963 tkey.expire = now + lifetime; 964 tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN; 965 if (nonce != NULL) 966 isc_buffer_usedregion(nonce, &r); 967 else { 968 r.base = isc_mem_get(msg->mctx, 0); 969 r.length = 0; 970 } 971 tkey.error = 0; 972 tkey.key = r.base; 973 tkey.keylen = r.length; 974 tkey.other = NULL; 975 tkey.otherlen = 0; 976 977 RETERR(buildquery(msg, name, &tkey, ISC_FALSE)); 978 979 if (nonce == NULL) 980 isc_mem_put(msg->mctx, r.base, 0); 981 982 RETERR(dns_message_gettemprdata(msg, &rdata)); 983 RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024)); 984 RETERR(dst_key_todns(key, dynbuf)); 985 isc_buffer_usedregion(dynbuf, &r); 986 dns_rdata_fromregion(rdata, dns_rdataclass_any, 987 dns_rdatatype_key, &r); 988 dns_message_takebuffer(msg, &dynbuf); 989 990 dns_name_init(&keyname, NULL); 991 dns_name_clone(dst_key_name(key), &keyname); 992 993 ISC_LIST_INIT(namelist); 994 RETERR(add_rdata_to_list(msg, &keyname, rdata, 0, &namelist)); 995 name = ISC_LIST_HEAD(namelist); 996 while (name != NULL) { 997 dns_name_t *next = ISC_LIST_NEXT(name, link); 998 ISC_LIST_UNLINK(namelist, name, link); 999 dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL); 1000 name = next; 1001 } 1002 1003 return (ISC_R_SUCCESS); 1004 1005 failure: 1006 1007 if (dynbuf != NULL) 1008 isc_buffer_free(&dynbuf); 1009 return (result); 1010} 1011 1012isc_result_t 1013dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, 1014 isc_buffer_t *intoken, isc_uint32_t lifetime, 1015 gss_ctx_id_t *context, isc_boolean_t win2k, 1016 isc_mem_t *mctx, char **err_message) 1017{ 1018 dns_rdata_tkey_t tkey; 1019 isc_result_t result; 1020 isc_stdtime_t now; 1021 isc_buffer_t token; 1022 unsigned char array[4096]; 1023 1024 UNUSED(intoken); 1025 1026 REQUIRE(msg != NULL); 1027 REQUIRE(name != NULL); 1028 REQUIRE(gname != NULL); 1029 REQUIRE(context != NULL); 1030 REQUIRE(mctx != NULL); 1031 1032 isc_buffer_init(&token, array, sizeof(array)); 1033 result = dst_gssapi_initctx(gname, NULL, &token, context, 1034 mctx, err_message); 1035 if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) 1036 return (result); 1037 1038 tkey.common.rdclass = dns_rdataclass_any; 1039 tkey.common.rdtype = dns_rdatatype_tkey; 1040 ISC_LINK_INIT(&tkey.common, link); 1041 tkey.mctx = NULL; 1042 dns_name_init(&tkey.algorithm, NULL); 1043 1044 if (win2k) 1045 dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); 1046 else 1047 dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); 1048 1049 isc_stdtime_get(&now); 1050 tkey.inception = now; 1051 tkey.expire = now + lifetime; 1052 tkey.mode = DNS_TKEYMODE_GSSAPI; 1053 tkey.error = 0; 1054 tkey.key = isc_buffer_base(&token); 1055 tkey.keylen = isc_buffer_usedlength(&token); 1056 tkey.other = NULL; 1057 tkey.otherlen = 0; 1058 1059 RETERR(buildquery(msg, name, &tkey, win2k)); 1060 1061 return (ISC_R_SUCCESS); 1062 1063 failure: 1064 return (result); 1065} 1066 1067isc_result_t 1068dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) { 1069 dns_rdata_tkey_t tkey; 1070 1071 REQUIRE(msg != NULL); 1072 REQUIRE(key != NULL); 1073 1074 tkey.common.rdclass = dns_rdataclass_any; 1075 tkey.common.rdtype = dns_rdatatype_tkey; 1076 ISC_LINK_INIT(&tkey.common, link); 1077 tkey.mctx = msg->mctx; 1078 dns_name_init(&tkey.algorithm, NULL); 1079 dns_name_clone(key->algorithm, &tkey.algorithm); 1080 tkey.inception = tkey.expire = 0; 1081 tkey.mode = DNS_TKEYMODE_DELETE; 1082 tkey.error = 0; 1083 tkey.keylen = tkey.otherlen = 0; 1084 tkey.key = tkey.other = NULL; 1085 1086 return (buildquery(msg, &key->name, &tkey, ISC_FALSE)); 1087} 1088 1089static isc_result_t 1090find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata, 1091 int section) 1092{ 1093 dns_rdataset_t *tkeyset; 1094 isc_result_t result; 1095 1096 result = dns_message_firstname(msg, section); 1097 while (result == ISC_R_SUCCESS) { 1098 *name = NULL; 1099 dns_message_currentname(msg, section, name); 1100 tkeyset = NULL; 1101 result = dns_message_findtype(*name, dns_rdatatype_tkey, 0, 1102 &tkeyset); 1103 if (result == ISC_R_SUCCESS) { 1104 result = dns_rdataset_first(tkeyset); 1105 if (result != ISC_R_SUCCESS) 1106 return (result); 1107 dns_rdataset_current(tkeyset, rdata); 1108 return (ISC_R_SUCCESS); 1109 } 1110 result = dns_message_nextname(msg, section); 1111 } 1112 if (result == ISC_R_NOMORE) 1113 return (ISC_R_NOTFOUND); 1114 return (result); 1115} 1116 1117isc_result_t 1118dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1119 dst_key_t *key, isc_buffer_t *nonce, 1120 dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring) 1121{ 1122 dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1123 dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname; 1124 dns_rdataset_t *theirkeyset = NULL, *ourkeyset = NULL; 1125 dns_rdata_t theirkeyrdata = DNS_RDATA_INIT; 1126 dst_key_t *theirkey = NULL; 1127 dns_rdata_tkey_t qtkey, rtkey; 1128 unsigned char secretdata[256]; 1129 unsigned int sharedsize; 1130 isc_buffer_t *shared = NULL, secret; 1131 isc_region_t r, r2; 1132 isc_result_t result; 1133 isc_boolean_t freertkey = ISC_FALSE; 1134 1135 REQUIRE(qmsg != NULL); 1136 REQUIRE(rmsg != NULL); 1137 REQUIRE(key != NULL); 1138 REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 1139 REQUIRE(dst_key_isprivate(key)); 1140 if (outkey != NULL) 1141 REQUIRE(*outkey == NULL); 1142 1143 if (rmsg->rcode != dns_rcode_noerror) 1144 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1145 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1146 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1147 freertkey = ISC_TRUE; 1148 1149 RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, 1150 DNS_SECTION_ADDITIONAL)); 1151 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1152 1153 if (rtkey.error != dns_rcode_noerror || 1154 rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN || 1155 rtkey.mode != qtkey.mode || 1156 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1157 rmsg->rcode != dns_rcode_noerror) { 1158 tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1159 "or error set(1)"); 1160 result = DNS_R_INVALIDTKEY; 1161 dns_rdata_freestruct(&qtkey); 1162 goto failure; 1163 } 1164 1165 dns_rdata_freestruct(&qtkey); 1166 1167 dns_name_init(&keyname, NULL); 1168 dns_name_clone(dst_key_name(key), &keyname); 1169 1170 ourkeyname = NULL; 1171 ourkeyset = NULL; 1172 RETERR(dns_message_findname(rmsg, DNS_SECTION_ANSWER, &keyname, 1173 dns_rdatatype_key, 0, &ourkeyname, 1174 &ourkeyset)); 1175 1176 result = dns_message_firstname(rmsg, DNS_SECTION_ANSWER); 1177 while (result == ISC_R_SUCCESS) { 1178 theirkeyname = NULL; 1179 dns_message_currentname(rmsg, DNS_SECTION_ANSWER, 1180 &theirkeyname); 1181 if (dns_name_equal(theirkeyname, ourkeyname)) 1182 goto next; 1183 theirkeyset = NULL; 1184 result = dns_message_findtype(theirkeyname, dns_rdatatype_key, 1185 0, &theirkeyset); 1186 if (result == ISC_R_SUCCESS) { 1187 RETERR(dns_rdataset_first(theirkeyset)); 1188 break; 1189 } 1190 next: 1191 result = dns_message_nextname(rmsg, DNS_SECTION_ANSWER); 1192 } 1193 1194 if (theirkeyset == NULL) { 1195 tkey_log("dns_tkey_processdhresponse: failed to find server " 1196 "key"); 1197 result = ISC_R_NOTFOUND; 1198 goto failure; 1199 } 1200 1201 dns_rdataset_current(theirkeyset, &theirkeyrdata); 1202 RETERR(dns_dnssec_keyfromrdata(theirkeyname, &theirkeyrdata, 1203 rmsg->mctx, &theirkey)); 1204 1205 RETERR(dst_key_secretsize(key, &sharedsize)); 1206 RETERR(isc_buffer_allocate(rmsg->mctx, &shared, sharedsize)); 1207 1208 RETERR(dst_key_computesecret(theirkey, key, shared)); 1209 1210 isc_buffer_init(&secret, secretdata, sizeof(secretdata)); 1211 1212 r.base = rtkey.key; 1213 r.length = rtkey.keylen; 1214 if (nonce != NULL) 1215 isc_buffer_usedregion(nonce, &r2); 1216 else { 1217 r2.base = isc_mem_get(rmsg->mctx, 0); 1218 r2.length = 0; 1219 } 1220 RETERR(compute_secret(shared, &r2, &r, &secret)); 1221 if (nonce == NULL) 1222 isc_mem_put(rmsg->mctx, r2.base, 0); 1223 1224 isc_buffer_usedregion(&secret, &r); 1225 result = dns_tsigkey_create(tkeyname, &rtkey.algorithm, 1226 r.base, r.length, ISC_TRUE, 1227 NULL, rtkey.inception, rtkey.expire, 1228 rmsg->mctx, ring, outkey); 1229 isc_buffer_free(&shared); 1230 dns_rdata_freestruct(&rtkey); 1231 dst_key_free(&theirkey); 1232 return (result); 1233 1234 failure: 1235 if (shared != NULL) 1236 isc_buffer_free(&shared); 1237 1238 if (theirkey != NULL) 1239 dst_key_free(&theirkey); 1240 1241 if (freertkey) 1242 dns_rdata_freestruct(&rtkey); 1243 1244 return (result); 1245} 1246 1247isc_result_t 1248dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1249 dns_name_t *gname, gss_ctx_id_t *context, 1250 isc_buffer_t *outtoken, dns_tsigkey_t **outkey, 1251 dns_tsig_keyring_t *ring, char **err_message) 1252{ 1253 dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1254 dns_name_t *tkeyname; 1255 dns_rdata_tkey_t rtkey, qtkey; 1256 dst_key_t *dstkey = NULL; 1257 isc_buffer_t intoken; 1258 isc_result_t result; 1259 unsigned char array[1024]; 1260 1261 REQUIRE(outtoken != NULL); 1262 REQUIRE(qmsg != NULL); 1263 REQUIRE(rmsg != NULL); 1264 REQUIRE(gname != NULL); 1265 REQUIRE(ring != NULL); 1266 if (outkey != NULL) 1267 REQUIRE(*outkey == NULL); 1268 1269 if (rmsg->rcode != dns_rcode_noerror) 1270 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1271 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1272 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1273 1274 /* 1275 * Win2k puts the item in the ANSWER section, while the RFC 1276 * specifies it should be in the ADDITIONAL section. Check first 1277 * where it should be, and then where it may be. 1278 */ 1279 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1280 DNS_SECTION_ADDITIONAL); 1281 if (result == ISC_R_NOTFOUND) 1282 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1283 DNS_SECTION_ANSWER); 1284 if (result != ISC_R_SUCCESS) 1285 goto failure; 1286 1287 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1288 1289 if (rtkey.error != dns_rcode_noerror || 1290 rtkey.mode != DNS_TKEYMODE_GSSAPI || 1291 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) { 1292 tkey_log("dns_tkey_processgssresponse: tkey mode invalid " 1293 "or error set(2) %d", rtkey.error); 1294 _dns_tkey_dumpmessage(qmsg); 1295 _dns_tkey_dumpmessage(rmsg); 1296 result = DNS_R_INVALIDTKEY; 1297 goto failure; 1298 } 1299 1300 isc_buffer_init(outtoken, array, sizeof(array)); 1301 isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1302 RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context, 1303 ring->mctx, err_message)); 1304 1305 RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, 1306 &dstkey, NULL)); 1307 1308 RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME, 1309 dstkey, ISC_FALSE, NULL, 1310 rtkey.inception, rtkey.expire, 1311 ring->mctx, ring, outkey)); 1312 dst_key_free(&dstkey); 1313 dns_rdata_freestruct(&rtkey); 1314 return (result); 1315 1316 failure: 1317 /* 1318 * XXXSRA This probably leaks memory from rtkey and qtkey. 1319 */ 1320 if (dstkey != NULL) 1321 dst_key_free(&dstkey); 1322 return (result); 1323} 1324 1325isc_result_t 1326dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1327 dns_tsig_keyring_t *ring) 1328{ 1329 dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1330 dns_name_t *tkeyname, *tempname; 1331 dns_rdata_tkey_t qtkey, rtkey; 1332 dns_tsigkey_t *tsigkey = NULL; 1333 isc_result_t result; 1334 1335 REQUIRE(qmsg != NULL); 1336 REQUIRE(rmsg != NULL); 1337 1338 if (rmsg->rcode != dns_rcode_noerror) 1339 return(ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1340 1341 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1342 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1343 1344 RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, 1345 DNS_SECTION_ADDITIONAL)); 1346 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1347 1348 if (rtkey.error != dns_rcode_noerror || 1349 rtkey.mode != DNS_TKEYMODE_DELETE || 1350 rtkey.mode != qtkey.mode || 1351 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1352 rmsg->rcode != dns_rcode_noerror) { 1353 tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid " 1354 "or error set(3)"); 1355 result = DNS_R_INVALIDTKEY; 1356 dns_rdata_freestruct(&qtkey); 1357 dns_rdata_freestruct(&rtkey); 1358 goto failure; 1359 } 1360 1361 dns_rdata_freestruct(&qtkey); 1362 1363 RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm, ring)); 1364 1365 dns_rdata_freestruct(&rtkey); 1366 1367 /* 1368 * Mark the key as deleted. 1369 */ 1370 dns_tsigkey_setdeleted(tsigkey); 1371 /* 1372 * Release the reference. 1373 */ 1374 dns_tsigkey_detach(&tsigkey); 1375 1376 failure: 1377 return (result); 1378} 1379 1380isc_result_t 1381dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, 1382 dns_name_t *server, gss_ctx_id_t *context, 1383 dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, 1384 isc_boolean_t win2k, char **err_message) 1385{ 1386 dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1387 dns_name_t *tkeyname; 1388 dns_rdata_tkey_t rtkey, qtkey; 1389 isc_buffer_t intoken, outtoken; 1390 dst_key_t *dstkey = NULL; 1391 isc_result_t result; 1392 unsigned char array[1024]; 1393 1394 REQUIRE(qmsg != NULL); 1395 REQUIRE(rmsg != NULL); 1396 REQUIRE(server != NULL); 1397 if (outkey != NULL) 1398 REQUIRE(*outkey == NULL); 1399 1400 if (rmsg->rcode != dns_rcode_noerror) 1401 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1402 1403 RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1404 RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1405 1406 if (win2k == ISC_TRUE) 1407 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1408 DNS_SECTION_ANSWER)); 1409 else 1410 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1411 DNS_SECTION_ADDITIONAL)); 1412 1413 RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1414 1415 if (rtkey.error != dns_rcode_noerror || 1416 rtkey.mode != DNS_TKEYMODE_GSSAPI || 1417 !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) 1418 { 1419 tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1420 "or error set(4)"); 1421 result = DNS_R_INVALIDTKEY; 1422 goto failure; 1423 } 1424 1425 isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1426 isc_buffer_init(&outtoken, array, sizeof(array)); 1427 1428 result = dst_gssapi_initctx(server, &intoken, &outtoken, context, 1429 ring->mctx, err_message); 1430 if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) 1431 return (result); 1432 1433 RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, 1434 &dstkey, NULL)); 1435 1436 /* 1437 * XXXSRA This seems confused. If we got CONTINUE from initctx, 1438 * the GSS negotiation hasn't completed yet, so we can't sign 1439 * anything yet. 1440 */ 1441 1442 RETERR(dns_tsigkey_createfromkey(tkeyname, 1443 (win2k 1444 ? DNS_TSIG_GSSAPIMS_NAME 1445 : DNS_TSIG_GSSAPI_NAME), 1446 dstkey, ISC_TRUE, NULL, 1447 rtkey.inception, rtkey.expire, 1448 ring->mctx, ring, outkey)); 1449 dst_key_free(&dstkey); 1450 dns_rdata_freestruct(&rtkey); 1451 return (result); 1452 1453 failure: 1454 /* 1455 * XXXSRA This probably leaks memory from qtkey. 1456 */ 1457 dns_rdata_freestruct(&rtkey); 1458 if (dstkey != NULL) 1459 dst_key_free(&dstkey); 1460 return (result); 1461} 1462