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