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