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