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