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