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