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