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