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