]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/lib/dns/tkey.c
MFC r363988:
[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 = NULL;
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         RETERR(dns_message_gettemprdata(msg, &rdata));
1002         RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
1003         RETERR(dst_key_todns(key, dynbuf));
1004         isc_buffer_usedregion(dynbuf, &r);
1005         dns_rdata_fromregion(rdata, dns_rdataclass_any,
1006                              dns_rdatatype_key, &r);
1007         dns_message_takebuffer(msg, &dynbuf);
1008
1009         dns_name_init(&keyname, NULL);
1010         dns_name_clone(dst_key_name(key), &keyname);
1011
1012         ISC_LIST_INIT(namelist);
1013         RETERR(add_rdata_to_list(msg, &keyname, rdata, 0, &namelist));
1014         name = ISC_LIST_HEAD(namelist);
1015         while (name != NULL) {
1016                 dns_name_t *next = ISC_LIST_NEXT(name, link);
1017                 ISC_LIST_UNLINK(namelist, name, link);
1018                 dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
1019                 name = next;
1020         }
1021
1022         return (ISC_R_SUCCESS);
1023
1024  failure:
1025
1026         if (dynbuf != NULL)
1027                 isc_buffer_free(&dynbuf);
1028         return (result);
1029 }
1030
1031 isc_result_t
1032 dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
1033                        isc_buffer_t *intoken, isc_uint32_t lifetime,
1034                        gss_ctx_id_t *context, isc_boolean_t win2k,
1035                        isc_mem_t *mctx, char **err_message)
1036 {
1037         dns_rdata_tkey_t tkey;
1038         isc_result_t result;
1039         isc_stdtime_t now;
1040         isc_buffer_t token;
1041         unsigned char array[TEMP_BUFFER_SZ];
1042
1043         UNUSED(intoken);
1044
1045         REQUIRE(msg != NULL);
1046         REQUIRE(name != NULL);
1047         REQUIRE(gname != NULL);
1048         REQUIRE(context != NULL);
1049         REQUIRE(mctx != NULL);
1050
1051         isc_buffer_init(&token, array, sizeof(array));
1052         result = dst_gssapi_initctx(gname, NULL, &token, context,
1053                                     mctx, err_message);
1054         if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
1055                 return (result);
1056
1057         tkey.common.rdclass = dns_rdataclass_any;
1058         tkey.common.rdtype = dns_rdatatype_tkey;
1059         ISC_LINK_INIT(&tkey.common, link);
1060         tkey.mctx = NULL;
1061         dns_name_init(&tkey.algorithm, NULL);
1062
1063         if (win2k)
1064                 dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm);
1065         else
1066                 dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm);
1067
1068         isc_stdtime_get(&now);
1069         tkey.inception = now;
1070         tkey.expire = now + lifetime;
1071         tkey.mode = DNS_TKEYMODE_GSSAPI;
1072         tkey.error = 0;
1073         tkey.key = isc_buffer_base(&token);
1074         tkey.keylen = isc_buffer_usedlength(&token);
1075         tkey.other = NULL;
1076         tkey.otherlen = 0;
1077
1078         return (buildquery(msg, name, &tkey, win2k));
1079 }
1080
1081 isc_result_t
1082 dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) {
1083         dns_rdata_tkey_t tkey;
1084
1085         REQUIRE(msg != NULL);
1086         REQUIRE(key != NULL);
1087
1088         tkey.common.rdclass = dns_rdataclass_any;
1089         tkey.common.rdtype = dns_rdatatype_tkey;
1090         ISC_LINK_INIT(&tkey.common, link);
1091         tkey.mctx = msg->mctx;
1092         dns_name_init(&tkey.algorithm, NULL);
1093         dns_name_clone(key->algorithm, &tkey.algorithm);
1094         tkey.inception = tkey.expire = 0;
1095         tkey.mode = DNS_TKEYMODE_DELETE;
1096         tkey.error = 0;
1097         tkey.keylen = tkey.otherlen = 0;
1098         tkey.key = tkey.other = NULL;
1099
1100         return (buildquery(msg, &key->name, &tkey, ISC_FALSE));
1101 }
1102
1103 static isc_result_t
1104 find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata,
1105           int section)
1106 {
1107         dns_rdataset_t *tkeyset;
1108         isc_result_t result;
1109
1110         result = dns_message_firstname(msg, section);
1111         while (result == ISC_R_SUCCESS) {
1112                 *name = NULL;
1113                 dns_message_currentname(msg, section, name);
1114                 tkeyset = NULL;
1115                 result = dns_message_findtype(*name, dns_rdatatype_tkey, 0,
1116                                               &tkeyset);
1117                 if (result == ISC_R_SUCCESS) {
1118                         result = dns_rdataset_first(tkeyset);
1119                         if (result != ISC_R_SUCCESS)
1120                                 return (result);
1121                         dns_rdataset_current(tkeyset, rdata);
1122                         return (ISC_R_SUCCESS);
1123                 }
1124                 result = dns_message_nextname(msg, section);
1125         }
1126         if (result == ISC_R_NOMORE)
1127                 return (ISC_R_NOTFOUND);
1128         return (result);
1129 }
1130
1131 isc_result_t
1132 dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
1133                            dst_key_t *key, isc_buffer_t *nonce,
1134                            dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring)
1135 {
1136         dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT;
1137         dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname;
1138         dns_rdataset_t *theirkeyset = NULL, *ourkeyset = NULL;
1139         dns_rdata_t theirkeyrdata = DNS_RDATA_INIT;
1140         dst_key_t *theirkey = NULL;
1141         dns_rdata_tkey_t qtkey, rtkey;
1142         unsigned char secretdata[256];
1143         unsigned int sharedsize;
1144         isc_buffer_t *shared = NULL, secret;
1145         isc_region_t r, r2;
1146         isc_result_t result;
1147         isc_boolean_t freertkey = ISC_FALSE;
1148
1149         REQUIRE(qmsg != NULL);
1150         REQUIRE(rmsg != NULL);
1151         REQUIRE(key != NULL);
1152         REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH);
1153         REQUIRE(dst_key_isprivate(key));
1154         if (outkey != NULL)
1155                 REQUIRE(*outkey == NULL);
1156
1157         if (rmsg->rcode != dns_rcode_noerror)
1158                 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
1159         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
1160         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
1161         freertkey = ISC_TRUE;
1162
1163         RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata,
1164                          DNS_SECTION_ADDITIONAL));
1165         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
1166
1167         if (rtkey.error != dns_rcode_noerror ||
1168             rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN ||
1169             rtkey.mode != qtkey.mode ||
1170             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
1171             rmsg->rcode != dns_rcode_noerror) {
1172                 tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
1173                          "or error set(1)");
1174                 result = DNS_R_INVALIDTKEY;
1175                 dns_rdata_freestruct(&qtkey);
1176                 goto failure;
1177         }
1178
1179         dns_rdata_freestruct(&qtkey);
1180
1181         dns_name_init(&keyname, NULL);
1182         dns_name_clone(dst_key_name(key), &keyname);
1183
1184         ourkeyname = NULL;
1185         ourkeyset = NULL;
1186         RETERR(dns_message_findname(rmsg, DNS_SECTION_ANSWER, &keyname,
1187                                     dns_rdatatype_key, 0, &ourkeyname,
1188                                     &ourkeyset));
1189
1190         result = dns_message_firstname(rmsg, DNS_SECTION_ANSWER);
1191         while (result == ISC_R_SUCCESS) {
1192                 theirkeyname = NULL;
1193                 dns_message_currentname(rmsg, DNS_SECTION_ANSWER,
1194                                         &theirkeyname);
1195                 if (dns_name_equal(theirkeyname, ourkeyname))
1196                         goto next;
1197                 theirkeyset = NULL;
1198                 result = dns_message_findtype(theirkeyname, dns_rdatatype_key,
1199                                               0, &theirkeyset);
1200                 if (result == ISC_R_SUCCESS) {
1201                         RETERR(dns_rdataset_first(theirkeyset));
1202                         break;
1203                 }
1204  next:
1205                 result = dns_message_nextname(rmsg, DNS_SECTION_ANSWER);
1206         }
1207
1208         if (theirkeyset == NULL) {
1209                 tkey_log("dns_tkey_processdhresponse: failed to find server "
1210                          "key");
1211                 result = ISC_R_NOTFOUND;
1212                 goto failure;
1213         }
1214
1215         dns_rdataset_current(theirkeyset, &theirkeyrdata);
1216         RETERR(dns_dnssec_keyfromrdata(theirkeyname, &theirkeyrdata,
1217                                        rmsg->mctx, &theirkey));
1218
1219         RETERR(dst_key_secretsize(key, &sharedsize));
1220         RETERR(isc_buffer_allocate(rmsg->mctx, &shared, sharedsize));
1221
1222         RETERR(dst_key_computesecret(theirkey, key, shared));
1223
1224         isc_buffer_init(&secret, secretdata, sizeof(secretdata));
1225
1226         r.base = rtkey.key;
1227         r.length = rtkey.keylen;
1228         if (nonce != NULL)
1229                 isc_buffer_usedregion(nonce, &r2);
1230         else {
1231                 r2.base = NULL;
1232                 r2.length = 0;
1233         }
1234         RETERR(compute_secret(shared, &r2, &r, &secret));
1235
1236         isc_buffer_usedregion(&secret, &r);
1237         result = dns_tsigkey_create(tkeyname, &rtkey.algorithm,
1238                                     r.base, r.length, ISC_TRUE,
1239                                     NULL, rtkey.inception, rtkey.expire,
1240                                     rmsg->mctx, ring, outkey);
1241         isc_buffer_free(&shared);
1242         dns_rdata_freestruct(&rtkey);
1243         dst_key_free(&theirkey);
1244         return (result);
1245
1246  failure:
1247         if (shared != NULL)
1248                 isc_buffer_free(&shared);
1249
1250         if (theirkey != NULL)
1251                 dst_key_free(&theirkey);
1252
1253         if (freertkey)
1254                 dns_rdata_freestruct(&rtkey);
1255
1256         return (result);
1257 }
1258
1259 isc_result_t
1260 dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
1261                             dns_name_t *gname, gss_ctx_id_t *context,
1262                             isc_buffer_t *outtoken, dns_tsigkey_t **outkey,
1263                             dns_tsig_keyring_t *ring, char **err_message)
1264 {
1265         dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
1266         dns_name_t *tkeyname;
1267         dns_rdata_tkey_t rtkey, qtkey;
1268         dst_key_t *dstkey = NULL;
1269         isc_buffer_t intoken;
1270         isc_result_t result;
1271         unsigned char array[1024];
1272
1273         REQUIRE(outtoken != NULL);
1274         REQUIRE(qmsg != NULL);
1275         REQUIRE(rmsg != NULL);
1276         REQUIRE(gname != NULL);
1277         REQUIRE(ring != NULL);
1278         if (outkey != NULL)
1279                 REQUIRE(*outkey == NULL);
1280
1281         if (rmsg->rcode != dns_rcode_noerror)
1282                 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
1283         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
1284         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
1285
1286         /*
1287          * Win2k puts the item in the ANSWER section, while the RFC
1288          * specifies it should be in the ADDITIONAL section.  Check first
1289          * where it should be, and then where it may be.
1290          */
1291         result = find_tkey(qmsg, &tkeyname, &qtkeyrdata,
1292                            DNS_SECTION_ADDITIONAL);
1293         if (result == ISC_R_NOTFOUND)
1294                 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata,
1295                                    DNS_SECTION_ANSWER);
1296         if (result != ISC_R_SUCCESS)
1297                 goto failure;
1298
1299         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
1300
1301         if (rtkey.error != dns_rcode_noerror ||
1302             rtkey.mode != DNS_TKEYMODE_GSSAPI ||
1303             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) {
1304                 tkey_log("dns_tkey_processgssresponse: tkey mode invalid "
1305                          "or error set(2) %d", rtkey.error);
1306                 dumpmessage(qmsg);
1307                 dumpmessage(rmsg);
1308                 result = DNS_R_INVALIDTKEY;
1309                 goto failure;
1310         }
1311
1312         isc_buffer_init(outtoken, array, sizeof(array));
1313         isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
1314         RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context,
1315                                   ring->mctx, err_message));
1316
1317         RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
1318                                   &dstkey, NULL));
1319
1320         RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME,
1321                                          dstkey, ISC_FALSE, NULL,
1322                                          rtkey.inception, rtkey.expire,
1323                                          ring->mctx, ring, outkey));
1324         dst_key_free(&dstkey);
1325         dns_rdata_freestruct(&rtkey);
1326         return (result);
1327
1328  failure:
1329         /*
1330          * XXXSRA This probably leaks memory from rtkey and qtkey.
1331          */
1332         if (dstkey != NULL)
1333                 dst_key_free(&dstkey);
1334         return (result);
1335 }
1336
1337 isc_result_t
1338 dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
1339                                dns_tsig_keyring_t *ring)
1340 {
1341         dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT;
1342         dns_name_t *tkeyname, *tempname;
1343         dns_rdata_tkey_t qtkey, rtkey;
1344         dns_tsigkey_t *tsigkey = NULL;
1345         isc_result_t result;
1346
1347         REQUIRE(qmsg != NULL);
1348         REQUIRE(rmsg != NULL);
1349
1350         if (rmsg->rcode != dns_rcode_noerror)
1351                 return(ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
1352
1353         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
1354         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
1355
1356         RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata,
1357                          DNS_SECTION_ADDITIONAL));
1358         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
1359
1360         if (rtkey.error != dns_rcode_noerror ||
1361             rtkey.mode != DNS_TKEYMODE_DELETE ||
1362             rtkey.mode != qtkey.mode ||
1363             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
1364             rmsg->rcode != dns_rcode_noerror) {
1365                 tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid "
1366                          "or error set(3)");
1367                 result = DNS_R_INVALIDTKEY;
1368                 dns_rdata_freestruct(&qtkey);
1369                 dns_rdata_freestruct(&rtkey);
1370                 goto failure;
1371         }
1372
1373         dns_rdata_freestruct(&qtkey);
1374
1375         RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm, ring));
1376
1377         dns_rdata_freestruct(&rtkey);
1378
1379         /*
1380          * Mark the key as deleted.
1381          */
1382         dns_tsigkey_setdeleted(tsigkey);
1383         /*
1384          * Release the reference.
1385          */
1386         dns_tsigkey_detach(&tsigkey);
1387
1388  failure:
1389         return (result);
1390 }
1391
1392 isc_result_t
1393 dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
1394                       dns_name_t *server, gss_ctx_id_t *context,
1395                       dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
1396                       isc_boolean_t win2k, char **err_message)
1397 {
1398         dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
1399         dns_name_t *tkeyname;
1400         dns_rdata_tkey_t rtkey, qtkey;
1401         isc_buffer_t intoken, outtoken;
1402         dst_key_t *dstkey = NULL;
1403         isc_result_t result;
1404         unsigned char array[1024];
1405         isc_boolean_t freertkey = ISC_FALSE;
1406
1407         REQUIRE(qmsg != NULL);
1408         REQUIRE(rmsg != NULL);
1409         REQUIRE(server != NULL);
1410         if (outkey != NULL)
1411                 REQUIRE(*outkey == NULL);
1412
1413         if (rmsg->rcode != dns_rcode_noerror)
1414                 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
1415
1416         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
1417         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
1418         freertkey = ISC_TRUE;
1419
1420         if (win2k == ISC_TRUE)
1421                 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
1422                                  DNS_SECTION_ANSWER));
1423         else
1424                 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
1425                                  DNS_SECTION_ADDITIONAL));
1426
1427         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
1428
1429         if (rtkey.error != dns_rcode_noerror ||
1430             rtkey.mode != DNS_TKEYMODE_GSSAPI ||
1431             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm))
1432         {
1433                 tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
1434                          "or error set(4)");
1435                 result = DNS_R_INVALIDTKEY;
1436                 goto failure;
1437         }
1438
1439         isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
1440         isc_buffer_init(&outtoken, array, sizeof(array));
1441
1442         result = dst_gssapi_initctx(server, &intoken, &outtoken, context,
1443                                     ring->mctx, err_message);
1444         if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
1445                 return (result);
1446
1447         RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
1448                                   &dstkey, NULL));
1449
1450         /*
1451          * XXXSRA This seems confused.  If we got CONTINUE from initctx,
1452          * the GSS negotiation hasn't completed yet, so we can't sign
1453          * anything yet.
1454          */
1455
1456         RETERR(dns_tsigkey_createfromkey(tkeyname,
1457                                          (win2k
1458                                           ? DNS_TSIG_GSSAPIMS_NAME
1459                                           : DNS_TSIG_GSSAPI_NAME),
1460                                          dstkey, ISC_TRUE, NULL,
1461                                          rtkey.inception, rtkey.expire,
1462                                          ring->mctx, ring, outkey));
1463         dst_key_free(&dstkey);
1464         dns_rdata_freestruct(&rtkey);
1465         return (result);
1466
1467  failure:
1468         /*
1469          * XXXSRA This probably leaks memory from qtkey.
1470          */
1471         if (freertkey)
1472                 dns_rdata_freestruct(&rtkey);
1473         if (dstkey != NULL)
1474                 dst_key_free(&dstkey);
1475         return (result);
1476 }