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