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