1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2001, 2003 Internet Software Consortium. 4135446Strhodes * 5186462Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18135446Strhodes/* 19234010Sdougb * $Id$ 20135446Strhodes */ 21170222Sdougb/*! \file */ 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <isc/buffer.h> 25135446Strhodes#include <isc/entropy.h> 26135446Strhodes#include <isc/md5.h> 27135446Strhodes#include <isc/mem.h> 28135446Strhodes#include <isc/string.h> 29135446Strhodes#include <isc/util.h> 30135446Strhodes 31135446Strhodes#include <dns/dnssec.h> 32135446Strhodes#include <dns/fixedname.h> 33135446Strhodes#include <dns/keyvalues.h> 34135446Strhodes#include <dns/log.h> 35135446Strhodes#include <dns/message.h> 36135446Strhodes#include <dns/name.h> 37135446Strhodes#include <dns/rdata.h> 38135446Strhodes#include <dns/rdatalist.h> 39135446Strhodes#include <dns/rdataset.h> 40135446Strhodes#include <dns/rdatastruct.h> 41135446Strhodes#include <dns/result.h> 42135446Strhodes#include <dns/tkey.h> 43135446Strhodes#include <dns/tsig.h> 44135446Strhodes 45135446Strhodes#include <dst/dst.h> 46135446Strhodes#include <dst/gssapi.h> 47135446Strhodes 48135446Strhodes#define TKEY_RANDOM_AMOUNT 16 49135446Strhodes 50135446Strhodes#define RETERR(x) do { \ 51135446Strhodes result = (x); \ 52135446Strhodes if (result != ISC_R_SUCCESS) \ 53135446Strhodes goto failure; \ 54135446Strhodes } while (0) 55135446Strhodes 56135446Strhodesstatic void 57135446Strhodestkey_log(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2); 58135446Strhodes 59135446Strhodesstatic void 60135446Strhodestkey_log(const char *fmt, ...) { 61135446Strhodes va_list ap; 62135446Strhodes 63135446Strhodes va_start(ap, fmt); 64135446Strhodes isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, 65135446Strhodes DNS_LOGMODULE_REQUEST, ISC_LOG_DEBUG(4), fmt, ap); 66135446Strhodes va_end(ap); 67135446Strhodes} 68135446Strhodes 69193149Sdougbstatic void 70193149Sdougb_dns_tkey_dumpmessage(dns_message_t *msg) { 71193149Sdougb isc_buffer_t outbuf; 72193149Sdougb unsigned char output[4096]; 73193149Sdougb isc_result_t result; 74193149Sdougb 75193149Sdougb isc_buffer_init(&outbuf, output, sizeof(output)); 76193149Sdougb result = dns_message_totext(msg, &dns_master_style_debug, 0, 77193149Sdougb &outbuf); 78225361Sdougb if (result != ISC_R_SUCCESS) 79225361Sdougb fprintf(stderr, "Warning: dns_message_totext returned: %s\n", 80225361Sdougb dns_result_totext(result)); 81193149Sdougb fprintf(stderr, "%.*s\n", (int)isc_buffer_usedlength(&outbuf), 82193149Sdougb (char *)isc_buffer_base(&outbuf)); 83193149Sdougb} 84193149Sdougb 85135446Strhodesisc_result_t 86135446Strhodesdns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp) 87135446Strhodes{ 88135446Strhodes dns_tkeyctx_t *tctx; 89135446Strhodes 90135446Strhodes REQUIRE(mctx != NULL); 91135446Strhodes REQUIRE(ectx != NULL); 92135446Strhodes REQUIRE(tctxp != NULL && *tctxp == NULL); 93135446Strhodes 94135446Strhodes tctx = isc_mem_get(mctx, sizeof(dns_tkeyctx_t)); 95135446Strhodes if (tctx == NULL) 96135446Strhodes return (ISC_R_NOMEMORY); 97135446Strhodes tctx->mctx = NULL; 98135446Strhodes isc_mem_attach(mctx, &tctx->mctx); 99135446Strhodes tctx->ectx = NULL; 100135446Strhodes isc_entropy_attach(ectx, &tctx->ectx); 101135446Strhodes tctx->dhkey = NULL; 102135446Strhodes tctx->domain = NULL; 103135446Strhodes tctx->gsscred = NULL; 104224092Sdougb tctx->gssapi_keytab = NULL; 105135446Strhodes 106135446Strhodes *tctxp = tctx; 107135446Strhodes return (ISC_R_SUCCESS); 108135446Strhodes} 109135446Strhodes 110135446Strhodesvoid 111135446Strhodesdns_tkeyctx_destroy(dns_tkeyctx_t **tctxp) { 112135446Strhodes isc_mem_t *mctx; 113135446Strhodes dns_tkeyctx_t *tctx; 114135446Strhodes 115135446Strhodes REQUIRE(tctxp != NULL && *tctxp != NULL); 116135446Strhodes 117135446Strhodes tctx = *tctxp; 118135446Strhodes mctx = tctx->mctx; 119135446Strhodes 120135446Strhodes if (tctx->dhkey != NULL) 121135446Strhodes dst_key_free(&tctx->dhkey); 122135446Strhodes if (tctx->domain != NULL) { 123135446Strhodes if (dns_name_dynamic(tctx->domain)) 124135446Strhodes dns_name_free(tctx->domain, mctx); 125135446Strhodes isc_mem_put(mctx, tctx->domain, sizeof(dns_name_t)); 126135446Strhodes } 127224092Sdougb if (tctx->gssapi_keytab != NULL) { 128224092Sdougb isc_mem_free(mctx, tctx->gssapi_keytab); 129224092Sdougb } 130193149Sdougb if (tctx->gsscred != NULL) 131193149Sdougb dst_gssapi_releasecred(&tctx->gsscred); 132135446Strhodes isc_entropy_detach(&tctx->ectx); 133135446Strhodes isc_mem_put(mctx, tctx, sizeof(dns_tkeyctx_t)); 134135446Strhodes isc_mem_detach(&mctx); 135135446Strhodes *tctxp = NULL; 136135446Strhodes} 137135446Strhodes 138135446Strhodesstatic isc_result_t 139135446Strhodesadd_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata, 140135446Strhodes isc_uint32_t ttl, dns_namelist_t *namelist) 141135446Strhodes{ 142135446Strhodes isc_result_t result; 143135446Strhodes isc_region_t r, newr; 144135446Strhodes dns_rdata_t *newrdata = NULL; 145135446Strhodes dns_name_t *newname = NULL; 146135446Strhodes dns_rdatalist_t *newlist = NULL; 147135446Strhodes dns_rdataset_t *newset = NULL; 148135446Strhodes isc_buffer_t *tmprdatabuf = NULL; 149135446Strhodes 150135446Strhodes RETERR(dns_message_gettemprdata(msg, &newrdata)); 151135446Strhodes 152135446Strhodes dns_rdata_toregion(rdata, &r); 153135446Strhodes RETERR(isc_buffer_allocate(msg->mctx, &tmprdatabuf, r.length)); 154135446Strhodes isc_buffer_availableregion(tmprdatabuf, &newr); 155262706Serwin memmove(newr.base, r.base, r.length); 156135446Strhodes dns_rdata_fromregion(newrdata, rdata->rdclass, rdata->type, &newr); 157135446Strhodes dns_message_takebuffer(msg, &tmprdatabuf); 158135446Strhodes 159135446Strhodes RETERR(dns_message_gettempname(msg, &newname)); 160135446Strhodes dns_name_init(newname, NULL); 161135446Strhodes RETERR(dns_name_dup(name, msg->mctx, newname)); 162135446Strhodes 163135446Strhodes RETERR(dns_message_gettemprdatalist(msg, &newlist)); 164135446Strhodes newlist->rdclass = newrdata->rdclass; 165135446Strhodes newlist->type = newrdata->type; 166135446Strhodes newlist->covers = 0; 167135446Strhodes newlist->ttl = ttl; 168135446Strhodes ISC_LIST_INIT(newlist->rdata); 169135446Strhodes ISC_LIST_APPEND(newlist->rdata, newrdata, link); 170135446Strhodes 171135446Strhodes RETERR(dns_message_gettemprdataset(msg, &newset)); 172135446Strhodes dns_rdataset_init(newset); 173135446Strhodes RETERR(dns_rdatalist_tordataset(newlist, newset)); 174135446Strhodes 175135446Strhodes ISC_LIST_INIT(newname->list); 176135446Strhodes ISC_LIST_APPEND(newname->list, newset, link); 177135446Strhodes 178135446Strhodes ISC_LIST_APPEND(*namelist, newname, link); 179135446Strhodes 180135446Strhodes return (ISC_R_SUCCESS); 181135446Strhodes 182135446Strhodes failure: 183135446Strhodes if (newrdata != NULL) { 184225361Sdougb if (ISC_LINK_LINKED(newrdata, link)) { 185225361Sdougb INSIST(newlist != NULL); 186135446Strhodes ISC_LIST_UNLINK(newlist->rdata, newrdata, link); 187225361Sdougb } 188135446Strhodes dns_message_puttemprdata(msg, &newrdata); 189135446Strhodes } 190135446Strhodes if (newname != NULL) 191135446Strhodes dns_message_puttempname(msg, &newname); 192135446Strhodes if (newset != NULL) { 193135446Strhodes dns_rdataset_disassociate(newset); 194135446Strhodes dns_message_puttemprdataset(msg, &newset); 195135446Strhodes } 196135446Strhodes if (newlist != NULL) 197135446Strhodes dns_message_puttemprdatalist(msg, &newlist); 198135446Strhodes return (result); 199135446Strhodes} 200135446Strhodes 201135446Strhodesstatic void 202135446Strhodesfree_namelist(dns_message_t *msg, dns_namelist_t *namelist) { 203135446Strhodes dns_name_t *name; 204135446Strhodes dns_rdataset_t *set; 205135446Strhodes 206135446Strhodes while (!ISC_LIST_EMPTY(*namelist)) { 207135446Strhodes name = ISC_LIST_HEAD(*namelist); 208135446Strhodes ISC_LIST_UNLINK(*namelist, name, link); 209135446Strhodes while (!ISC_LIST_EMPTY(name->list)) { 210135446Strhodes set = ISC_LIST_HEAD(name->list); 211135446Strhodes ISC_LIST_UNLINK(name->list, set, link); 212135446Strhodes dns_message_puttemprdataset(msg, &set); 213135446Strhodes } 214135446Strhodes dns_message_puttempname(msg, &name); 215135446Strhodes } 216135446Strhodes} 217135446Strhodes 218135446Strhodesstatic isc_result_t 219135446Strhodescompute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness, 220135446Strhodes isc_region_t *serverrandomness, isc_buffer_t *secret) 221135446Strhodes{ 222135446Strhodes isc_md5_t md5ctx; 223135446Strhodes isc_region_t r, r2; 224135446Strhodes unsigned char digests[32]; 225135446Strhodes unsigned int i; 226135446Strhodes 227135446Strhodes isc_buffer_usedregion(shared, &r); 228135446Strhodes 229135446Strhodes /* 230135446Strhodes * MD5 ( query data | DH value ). 231135446Strhodes */ 232135446Strhodes isc_md5_init(&md5ctx); 233135446Strhodes isc_md5_update(&md5ctx, queryrandomness->base, 234135446Strhodes queryrandomness->length); 235135446Strhodes isc_md5_update(&md5ctx, r.base, r.length); 236135446Strhodes isc_md5_final(&md5ctx, digests); 237135446Strhodes 238135446Strhodes /* 239135446Strhodes * MD5 ( server data | DH value ). 240135446Strhodes */ 241135446Strhodes isc_md5_init(&md5ctx); 242135446Strhodes isc_md5_update(&md5ctx, serverrandomness->base, 243135446Strhodes serverrandomness->length); 244135446Strhodes isc_md5_update(&md5ctx, r.base, r.length); 245135446Strhodes isc_md5_final(&md5ctx, &digests[ISC_MD5_DIGESTLENGTH]); 246135446Strhodes 247135446Strhodes /* 248135446Strhodes * XOR ( DH value, MD5-1 | MD5-2). 249135446Strhodes */ 250135446Strhodes isc_buffer_availableregion(secret, &r); 251135446Strhodes isc_buffer_usedregion(shared, &r2); 252135446Strhodes if (r.length < sizeof(digests) || r.length < r2.length) 253135446Strhodes return (ISC_R_NOSPACE); 254135446Strhodes if (r2.length > sizeof(digests)) { 255262706Serwin memmove(r.base, r2.base, r2.length); 256135446Strhodes for (i = 0; i < sizeof(digests); i++) 257135446Strhodes r.base[i] ^= digests[i]; 258135446Strhodes isc_buffer_add(secret, r2.length); 259135446Strhodes } else { 260262706Serwin memmove(r.base, digests, sizeof(digests)); 261135446Strhodes for (i = 0; i < r2.length; i++) 262135446Strhodes r.base[i] ^= r2.base[i]; 263135446Strhodes isc_buffer_add(secret, sizeof(digests)); 264135446Strhodes } 265135446Strhodes return (ISC_R_SUCCESS); 266135446Strhodes 267135446Strhodes} 268135446Strhodes 269135446Strhodesstatic isc_result_t 270135446Strhodesprocess_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, 271135446Strhodes dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx, 272135446Strhodes dns_rdata_tkey_t *tkeyout, 273135446Strhodes dns_tsig_keyring_t *ring, dns_namelist_t *namelist) 274135446Strhodes{ 275135446Strhodes isc_result_t result = ISC_R_SUCCESS; 276135446Strhodes dns_name_t *keyname, ourname; 277135446Strhodes dns_rdataset_t *keyset = NULL; 278135446Strhodes dns_rdata_t keyrdata = DNS_RDATA_INIT, ourkeyrdata = DNS_RDATA_INIT; 279135446Strhodes isc_boolean_t found_key = ISC_FALSE, found_incompatible = ISC_FALSE; 280135446Strhodes dst_key_t *pubkey = NULL; 281135446Strhodes isc_buffer_t ourkeybuf, *shared = NULL; 282135446Strhodes isc_region_t r, r2, ourkeyr; 283135446Strhodes unsigned char keydata[DST_KEY_MAXSIZE]; 284135446Strhodes unsigned int sharedsize; 285135446Strhodes isc_buffer_t secret; 286135446Strhodes unsigned char *randomdata = NULL, secretdata[256]; 287135446Strhodes dns_ttl_t ttl = 0; 288135446Strhodes 289135446Strhodes if (tctx->dhkey == NULL) { 290135446Strhodes tkey_log("process_dhtkey: tkey-dhkey not defined"); 291135446Strhodes tkeyout->error = dns_tsigerror_badalg; 292135446Strhodes return (DNS_R_REFUSED); 293135446Strhodes } 294135446Strhodes 295135446Strhodes if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) { 296135446Strhodes tkey_log("process_dhtkey: algorithms other than " 297135446Strhodes "hmac-md5 are not supported"); 298135446Strhodes tkeyout->error = dns_tsigerror_badalg; 299135446Strhodes return (ISC_R_SUCCESS); 300135446Strhodes } 301135446Strhodes 302135446Strhodes /* 303135446Strhodes * Look for a DH KEY record that will work with ours. 304135446Strhodes */ 305135446Strhodes for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL); 306135446Strhodes result == ISC_R_SUCCESS && !found_key; 307193149Sdougb result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) { 308135446Strhodes keyname = NULL; 309135446Strhodes dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname); 310135446Strhodes keyset = NULL; 311135446Strhodes result = dns_message_findtype(keyname, dns_rdatatype_key, 0, 312135446Strhodes &keyset); 313135446Strhodes if (result != ISC_R_SUCCESS) 314135446Strhodes continue; 315135446Strhodes 316135446Strhodes for (result = dns_rdataset_first(keyset); 317135446Strhodes result == ISC_R_SUCCESS && !found_key; 318193149Sdougb result = dns_rdataset_next(keyset)) { 319135446Strhodes dns_rdataset_current(keyset, &keyrdata); 320135446Strhodes pubkey = NULL; 321135446Strhodes result = dns_dnssec_keyfromrdata(keyname, &keyrdata, 322135446Strhodes msg->mctx, &pubkey); 323135446Strhodes if (result != ISC_R_SUCCESS) { 324135446Strhodes dns_rdata_reset(&keyrdata); 325135446Strhodes continue; 326135446Strhodes } 327135446Strhodes if (dst_key_alg(pubkey) == DNS_KEYALG_DH) { 328135446Strhodes if (dst_key_paramcompare(pubkey, tctx->dhkey)) 329135446Strhodes { 330135446Strhodes found_key = ISC_TRUE; 331135446Strhodes ttl = keyset->ttl; 332135446Strhodes break; 333135446Strhodes } else 334135446Strhodes found_incompatible = ISC_TRUE; 335135446Strhodes } 336135446Strhodes dst_key_free(&pubkey); 337135446Strhodes dns_rdata_reset(&keyrdata); 338135446Strhodes } 339135446Strhodes } 340135446Strhodes 341135446Strhodes if (!found_key) { 342135446Strhodes if (found_incompatible) { 343135446Strhodes tkey_log("process_dhtkey: found an incompatible key"); 344135446Strhodes tkeyout->error = dns_tsigerror_badkey; 345135446Strhodes return (ISC_R_SUCCESS); 346135446Strhodes } else { 347135446Strhodes tkey_log("process_dhtkey: failed to find a key"); 348135446Strhodes return (DNS_R_FORMERR); 349135446Strhodes } 350135446Strhodes } 351135446Strhodes 352135446Strhodes RETERR(add_rdata_to_list(msg, keyname, &keyrdata, ttl, namelist)); 353135446Strhodes 354135446Strhodes isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata)); 355135446Strhodes RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf)); 356135446Strhodes isc_buffer_usedregion(&ourkeybuf, &ourkeyr); 357135446Strhodes dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_any, 358135446Strhodes dns_rdatatype_key, &ourkeyr); 359135446Strhodes 360135446Strhodes dns_name_init(&ourname, NULL); 361135446Strhodes dns_name_clone(dst_key_name(tctx->dhkey), &ourname); 362135446Strhodes 363135446Strhodes /* 364135446Strhodes * XXXBEW The TTL should be obtained from the database, if it exists. 365135446Strhodes */ 366135446Strhodes RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, 0, namelist)); 367135446Strhodes 368135446Strhodes RETERR(dst_key_secretsize(tctx->dhkey, &sharedsize)); 369135446Strhodes RETERR(isc_buffer_allocate(msg->mctx, &shared, sharedsize)); 370135446Strhodes 371135446Strhodes result = dst_key_computesecret(pubkey, tctx->dhkey, shared); 372135446Strhodes if (result != ISC_R_SUCCESS) { 373135446Strhodes tkey_log("process_dhtkey: failed to compute shared secret: %s", 374135446Strhodes isc_result_totext(result)); 375135446Strhodes goto failure; 376135446Strhodes } 377135446Strhodes dst_key_free(&pubkey); 378135446Strhodes 379135446Strhodes isc_buffer_init(&secret, secretdata, sizeof(secretdata)); 380135446Strhodes 381153816Sdougb randomdata = isc_mem_get(tkeyout->mctx, TKEY_RANDOM_AMOUNT); 382135446Strhodes if (randomdata == NULL) 383135446Strhodes goto failure; 384135446Strhodes 385135446Strhodes result = isc_entropy_getdata(tctx->ectx, randomdata, 386135446Strhodes TKEY_RANDOM_AMOUNT, NULL, 0); 387135446Strhodes if (result != ISC_R_SUCCESS) { 388135446Strhodes tkey_log("process_dhtkey: failed to obtain entropy: %s", 389135446Strhodes isc_result_totext(result)); 390135446Strhodes goto failure; 391135446Strhodes } 392135446Strhodes 393135446Strhodes r.base = randomdata; 394135446Strhodes r.length = TKEY_RANDOM_AMOUNT; 395135446Strhodes r2.base = tkeyin->key; 396135446Strhodes r2.length = tkeyin->keylen; 397135446Strhodes RETERR(compute_secret(shared, &r2, &r, &secret)); 398135446Strhodes isc_buffer_free(&shared); 399135446Strhodes 400135446Strhodes RETERR(dns_tsigkey_create(name, &tkeyin->algorithm, 401135446Strhodes isc_buffer_base(&secret), 402135446Strhodes isc_buffer_usedlength(&secret), 403135446Strhodes ISC_TRUE, signer, tkeyin->inception, 404186462Sdougb tkeyin->expire, ring->mctx, ring, NULL)); 405135446Strhodes 406135446Strhodes /* This key is good for a long time */ 407135446Strhodes tkeyout->inception = tkeyin->inception; 408135446Strhodes tkeyout->expire = tkeyin->expire; 409135446Strhodes 410135446Strhodes tkeyout->key = randomdata; 411135446Strhodes tkeyout->keylen = TKEY_RANDOM_AMOUNT; 412135446Strhodes 413135446Strhodes return (ISC_R_SUCCESS); 414135446Strhodes 415135446Strhodes failure: 416135446Strhodes if (!ISC_LIST_EMPTY(*namelist)) 417135446Strhodes free_namelist(msg, namelist); 418135446Strhodes if (shared != NULL) 419135446Strhodes isc_buffer_free(&shared); 420135446Strhodes if (pubkey != NULL) 421135446Strhodes dst_key_free(&pubkey); 422153816Sdougb if (randomdata != NULL) 423153816Sdougb isc_mem_put(tkeyout->mctx, randomdata, TKEY_RANDOM_AMOUNT); 424135446Strhodes return (result); 425135446Strhodes} 426135446Strhodes 427135446Strhodesstatic isc_result_t 428218384Sdougbprocess_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, 429218384Sdougb dns_tkeyctx_t *tctx, dns_rdata_tkey_t *tkeyout, 430218384Sdougb dns_tsig_keyring_t *ring) 431135446Strhodes{ 432135446Strhodes isc_result_t result = ISC_R_SUCCESS; 433135446Strhodes dst_key_t *dstkey = NULL; 434193149Sdougb dns_tsigkey_t *tsigkey = NULL; 435193149Sdougb dns_fixedname_t principal; 436135446Strhodes isc_stdtime_t now; 437135446Strhodes isc_region_t intoken; 438193149Sdougb isc_buffer_t *outtoken = NULL; 439193149Sdougb gss_ctx_id_t gss_ctx = NULL; 440135446Strhodes 441224092Sdougb /* 442224092Sdougb * You have to define either a gss credential (principal) to 443224092Sdougb * accept with tkey-gssapi-credential, or you have to 444224092Sdougb * configure a specific keytab (with tkey-gssapi-keytab) in 445224092Sdougb * order to use gsstkey 446224092Sdougb */ 447224092Sdougb if (tctx->gsscred == NULL && tctx->gssapi_keytab == NULL) { 448224092Sdougb tkey_log("process_gsstkey(): no tkey-gssapi-credential " 449224092Sdougb "or tkey-gssapi-keytab configured"); 450135446Strhodes return (ISC_R_NOPERM); 451224092Sdougb } 452135446Strhodes 453135446Strhodes if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) && 454135446Strhodes !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) { 455135446Strhodes tkeyout->error = dns_tsigerror_badalg; 456193149Sdougb tkey_log("process_gsstkey(): dns_tsigerror_badalg"); /* XXXSRA */ 457135446Strhodes return (ISC_R_SUCCESS); 458135446Strhodes } 459135446Strhodes 460193149Sdougb /* 461193149Sdougb * XXXDCL need to check for key expiry per 4.1.1 462193149Sdougb * XXXDCL need a way to check fully established, perhaps w/key_flags 463193149Sdougb */ 464193149Sdougb 465135446Strhodes intoken.base = tkeyin->key; 466135446Strhodes intoken.length = tkeyin->keylen; 467135446Strhodes 468193149Sdougb result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring); 469193149Sdougb if (result == ISC_R_SUCCESS) 470193149Sdougb gss_ctx = dst_key_getgssctx(tsigkey->key); 471135446Strhodes 472193149Sdougb dns_fixedname_init(&principal); 473193149Sdougb 474224092Sdougb /* 475224092Sdougb * Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set 476224092Sdougb */ 477224092Sdougb result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab, 478224092Sdougb &intoken, 479193149Sdougb &outtoken, &gss_ctx, 480193149Sdougb dns_fixedname_name(&principal), 481193149Sdougb tctx->mctx); 482193149Sdougb if (result == DNS_R_INVALIDTKEY) { 483218384Sdougb if (tsigkey != NULL) 484218384Sdougb dns_tsigkey_detach(&tsigkey); 485193149Sdougb tkeyout->error = dns_tsigerror_badkey; 486193149Sdougb tkey_log("process_gsstkey(): dns_tsigerror_badkey"); /* XXXSRA */ 487135446Strhodes return (ISC_R_SUCCESS); 488236374Sdougb } 489236374Sdougb if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) 490135446Strhodes goto failure; 491193149Sdougb /* 492193149Sdougb * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times. 493193149Sdougb */ 494135446Strhodes 495218384Sdougb isc_stdtime_get(&now); 496218384Sdougb 497193149Sdougb if (tsigkey == NULL) { 498218384Sdougb#ifdef GSSAPI 499218384Sdougb OM_uint32 gret, minor, lifetime; 500218384Sdougb#endif 501218384Sdougb isc_uint32_t expire; 502218384Sdougb 503224092Sdougb RETERR(dst_key_fromgssapi(name, gss_ctx, ring->mctx, 504224092Sdougb &dstkey, &intoken)); 505218384Sdougb /* 506218384Sdougb * Limit keys to 1 hour or the context's lifetime whichever 507218384Sdougb * is smaller. 508218384Sdougb */ 509218384Sdougb expire = now + 3600; 510218384Sdougb#ifdef GSSAPI 511218384Sdougb gret = gss_context_time(&minor, gss_ctx, &lifetime); 512218384Sdougb if (gret == GSS_S_COMPLETE && now + lifetime < expire) 513218384Sdougb expire = now + lifetime; 514218384Sdougb#endif 515193149Sdougb RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm, 516193149Sdougb dstkey, ISC_TRUE, 517193149Sdougb dns_fixedname_name(&principal), 518218384Sdougb now, expire, ring->mctx, ring, 519218384Sdougb NULL)); 520218384Sdougb dst_key_free(&dstkey); 521218384Sdougb tkeyout->inception = now; 522218384Sdougb tkeyout->expire = expire; 523218384Sdougb } else { 524218384Sdougb tkeyout->inception = tsigkey->inception; 525225361Sdougb tkeyout->expire = tsigkey->expire; 526218384Sdougb dns_tsigkey_detach(&tsigkey); 527193149Sdougb } 528193149Sdougb 529193149Sdougb if (outtoken) { 530193149Sdougb tkeyout->key = isc_mem_get(tkeyout->mctx, 531193149Sdougb isc_buffer_usedlength(outtoken)); 532193149Sdougb if (tkeyout->key == NULL) { 533193149Sdougb result = ISC_R_NOMEMORY; 534193149Sdougb goto failure; 535193149Sdougb } 536193149Sdougb tkeyout->keylen = isc_buffer_usedlength(outtoken); 537262706Serwin memmove(tkeyout->key, isc_buffer_base(outtoken), 538193149Sdougb isc_buffer_usedlength(outtoken)); 539193149Sdougb isc_buffer_free(&outtoken); 540193149Sdougb } else { 541193149Sdougb tkeyout->key = isc_mem_get(tkeyout->mctx, tkeyin->keylen); 542193149Sdougb if (tkeyout->key == NULL) { 543193149Sdougb result = ISC_R_NOMEMORY; 544193149Sdougb goto failure; 545193149Sdougb } 546193149Sdougb tkeyout->keylen = tkeyin->keylen; 547262706Serwin memmove(tkeyout->key, tkeyin->key, tkeyin->keylen); 548135446Strhodes } 549135446Strhodes 550193149Sdougb tkeyout->error = dns_rcode_noerror; 551193149Sdougb 552193149Sdougb tkey_log("process_gsstkey(): dns_tsigerror_noerror"); /* XXXSRA */ 553193149Sdougb 554135446Strhodes return (ISC_R_SUCCESS); 555135446Strhodes 556193149Sdougbfailure: 557218384Sdougb if (tsigkey != NULL) 558218384Sdougb dns_tsigkey_detach(&tsigkey); 559218384Sdougb 560135446Strhodes if (dstkey != NULL) 561135446Strhodes dst_key_free(&dstkey); 562135446Strhodes 563193149Sdougb if (outtoken != NULL) 564193149Sdougb isc_buffer_free(&outtoken); 565193149Sdougb 566193149Sdougb tkey_log("process_gsstkey(): %s", 567193149Sdougb isc_result_totext(result)); /* XXXSRA */ 568193149Sdougb 569135446Strhodes return (result); 570135446Strhodes} 571135446Strhodes 572135446Strhodesstatic isc_result_t 573218384Sdougbprocess_deletetkey(dns_name_t *signer, dns_name_t *name, 574218384Sdougb dns_rdata_tkey_t *tkeyin, dns_rdata_tkey_t *tkeyout, 575218384Sdougb dns_tsig_keyring_t *ring) 576135446Strhodes{ 577135446Strhodes isc_result_t result; 578135446Strhodes dns_tsigkey_t *tsigkey = NULL; 579135446Strhodes dns_name_t *identity; 580135446Strhodes 581135446Strhodes result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring); 582135446Strhodes if (result != ISC_R_SUCCESS) { 583135446Strhodes tkeyout->error = dns_tsigerror_badname; 584135446Strhodes return (ISC_R_SUCCESS); 585135446Strhodes } 586135446Strhodes 587135446Strhodes /* 588135446Strhodes * Only allow a delete if the identity that created the key is the 589135446Strhodes * same as the identity that signed the message. 590135446Strhodes */ 591135446Strhodes identity = dns_tsigkey_identity(tsigkey); 592135446Strhodes if (identity == NULL || !dns_name_equal(identity, signer)) { 593135446Strhodes dns_tsigkey_detach(&tsigkey); 594135446Strhodes return (DNS_R_REFUSED); 595135446Strhodes } 596135446Strhodes 597135446Strhodes /* 598135446Strhodes * Set the key to be deleted when no references are left. If the key 599135446Strhodes * was not generated with TKEY and is in the config file, it may be 600135446Strhodes * reloaded later. 601135446Strhodes */ 602135446Strhodes dns_tsigkey_setdeleted(tsigkey); 603135446Strhodes 604135446Strhodes /* Release the reference */ 605135446Strhodes dns_tsigkey_detach(&tsigkey); 606135446Strhodes 607135446Strhodes return (ISC_R_SUCCESS); 608135446Strhodes} 609135446Strhodes 610135446Strhodesisc_result_t 611135446Strhodesdns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, 612135446Strhodes dns_tsig_keyring_t *ring) 613135446Strhodes{ 614135446Strhodes isc_result_t result = ISC_R_SUCCESS; 615135446Strhodes dns_rdata_tkey_t tkeyin, tkeyout; 616135446Strhodes isc_boolean_t freetkeyin = ISC_FALSE; 617135446Strhodes dns_name_t *qname, *name, *keyname, *signer, tsigner; 618135446Strhodes dns_fixedname_t fkeyname; 619135446Strhodes dns_rdataset_t *tkeyset; 620135446Strhodes dns_rdata_t rdata; 621135446Strhodes dns_namelist_t namelist; 622135446Strhodes char tkeyoutdata[512]; 623135446Strhodes isc_buffer_t tkeyoutbuf; 624135446Strhodes 625135446Strhodes REQUIRE(msg != NULL); 626135446Strhodes REQUIRE(tctx != NULL); 627135446Strhodes REQUIRE(ring != NULL); 628135446Strhodes 629135446Strhodes ISC_LIST_INIT(namelist); 630135446Strhodes 631135446Strhodes /* 632135446Strhodes * Interpret the question section. 633135446Strhodes */ 634135446Strhodes result = dns_message_firstname(msg, DNS_SECTION_QUESTION); 635135446Strhodes if (result != ISC_R_SUCCESS) 636135446Strhodes return (DNS_R_FORMERR); 637135446Strhodes 638135446Strhodes qname = NULL; 639135446Strhodes dns_message_currentname(msg, DNS_SECTION_QUESTION, &qname); 640135446Strhodes 641135446Strhodes /* 642135446Strhodes * Look for a TKEY record that matches the question. 643135446Strhodes */ 644135446Strhodes tkeyset = NULL; 645135446Strhodes name = NULL; 646135446Strhodes result = dns_message_findname(msg, DNS_SECTION_ADDITIONAL, qname, 647135446Strhodes dns_rdatatype_tkey, 0, &name, &tkeyset); 648135446Strhodes if (result != ISC_R_SUCCESS) { 649135446Strhodes /* 650135446Strhodes * Try the answer section, since that's where Win2000 651135446Strhodes * puts it. 652135446Strhodes */ 653285980Sdelphij name = NULL; 654135446Strhodes if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 655135446Strhodes dns_rdatatype_tkey, 0, &name, 656193149Sdougb &tkeyset) != ISC_R_SUCCESS) { 657135446Strhodes result = DNS_R_FORMERR; 658135446Strhodes tkey_log("dns_tkey_processquery: couldn't find a TKEY " 659135446Strhodes "matching the question"); 660135446Strhodes goto failure; 661135446Strhodes } 662135446Strhodes } 663135446Strhodes result = dns_rdataset_first(tkeyset); 664135446Strhodes if (result != ISC_R_SUCCESS) { 665135446Strhodes result = DNS_R_FORMERR; 666135446Strhodes goto failure; 667135446Strhodes } 668135446Strhodes dns_rdata_init(&rdata); 669135446Strhodes dns_rdataset_current(tkeyset, &rdata); 670135446Strhodes 671135446Strhodes RETERR(dns_rdata_tostruct(&rdata, &tkeyin, NULL)); 672135446Strhodes freetkeyin = ISC_TRUE; 673135446Strhodes 674135446Strhodes if (tkeyin.error != dns_rcode_noerror) { 675135446Strhodes result = DNS_R_FORMERR; 676135446Strhodes goto failure; 677135446Strhodes } 678135446Strhodes 679135446Strhodes /* 680135446Strhodes * Before we go any farther, verify that the message was signed. 681135446Strhodes * GSSAPI TKEY doesn't require a signature, the rest do. 682135446Strhodes */ 683135446Strhodes dns_name_init(&tsigner, NULL); 684135446Strhodes result = dns_message_signer(msg, &tsigner); 685135446Strhodes if (result != ISC_R_SUCCESS) { 686135446Strhodes if (tkeyin.mode == DNS_TKEYMODE_GSSAPI && 687135446Strhodes result == ISC_R_NOTFOUND) 688135446Strhodes signer = NULL; 689135446Strhodes else { 690135446Strhodes tkey_log("dns_tkey_processquery: query was not " 691135446Strhodes "properly signed - rejecting"); 692135446Strhodes result = DNS_R_FORMERR; 693135446Strhodes goto failure; 694135446Strhodes } 695135446Strhodes } else 696135446Strhodes signer = &tsigner; 697135446Strhodes 698135446Strhodes tkeyout.common.rdclass = tkeyin.common.rdclass; 699135446Strhodes tkeyout.common.rdtype = tkeyin.common.rdtype; 700135446Strhodes ISC_LINK_INIT(&tkeyout.common, link); 701135446Strhodes tkeyout.mctx = msg->mctx; 702135446Strhodes 703135446Strhodes dns_name_init(&tkeyout.algorithm, NULL); 704135446Strhodes dns_name_clone(&tkeyin.algorithm, &tkeyout.algorithm); 705135446Strhodes 706135446Strhodes tkeyout.inception = tkeyout.expire = 0; 707135446Strhodes tkeyout.mode = tkeyin.mode; 708135446Strhodes tkeyout.error = 0; 709135446Strhodes tkeyout.keylen = tkeyout.otherlen = 0; 710135446Strhodes tkeyout.key = tkeyout.other = NULL; 711135446Strhodes 712135446Strhodes /* 713135446Strhodes * A delete operation must have a fully specified key name. If this 714135446Strhodes * is not a delete, we do the following: 715135446Strhodes * if (qname != ".") 716135446Strhodes * keyname = qname + defaultdomain 717135446Strhodes * else 718135446Strhodes * keyname = <random hex> + defaultdomain 719135446Strhodes */ 720135446Strhodes if (tkeyin.mode != DNS_TKEYMODE_DELETE) { 721135446Strhodes dns_tsigkey_t *tsigkey = NULL; 722135446Strhodes 723193149Sdougb if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) { 724135446Strhodes tkey_log("dns_tkey_processquery: tkey-domain not set"); 725135446Strhodes result = DNS_R_REFUSED; 726135446Strhodes goto failure; 727135446Strhodes } 728135446Strhodes 729135446Strhodes dns_fixedname_init(&fkeyname); 730135446Strhodes keyname = dns_fixedname_name(&fkeyname); 731135446Strhodes 732135446Strhodes if (!dns_name_equal(qname, dns_rootname)) { 733135446Strhodes unsigned int n = dns_name_countlabels(qname); 734135446Strhodes RUNTIME_CHECK(dns_name_copy(qname, keyname, NULL) 735135446Strhodes == ISC_R_SUCCESS); 736135446Strhodes dns_name_getlabelsequence(keyname, 0, n - 1, keyname); 737135446Strhodes } else { 738135446Strhodes static char hexdigits[16] = { 739135446Strhodes '0', '1', '2', '3', '4', '5', '6', '7', 740135446Strhodes '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 741135446Strhodes unsigned char randomdata[16]; 742135446Strhodes char randomtext[32]; 743135446Strhodes isc_buffer_t b; 744135446Strhodes unsigned int i, j; 745135446Strhodes 746135446Strhodes result = isc_entropy_getdata(tctx->ectx, 747135446Strhodes randomdata, 748135446Strhodes sizeof(randomdata), 749135446Strhodes NULL, 0); 750135446Strhodes if (result != ISC_R_SUCCESS) 751135446Strhodes goto failure; 752135446Strhodes 753135446Strhodes for (i = 0, j = 0; i < sizeof(randomdata); i++) { 754135446Strhodes unsigned char val = randomdata[i]; 755135446Strhodes randomtext[j++] = hexdigits[val >> 4]; 756135446Strhodes randomtext[j++] = hexdigits[val & 0xF]; 757135446Strhodes } 758135446Strhodes isc_buffer_init(&b, randomtext, sizeof(randomtext)); 759135446Strhodes isc_buffer_add(&b, sizeof(randomtext)); 760224092Sdougb result = dns_name_fromtext(keyname, &b, NULL, 0, NULL); 761135446Strhodes if (result != ISC_R_SUCCESS) 762135446Strhodes goto failure; 763135446Strhodes } 764135446Strhodes 765193149Sdougb if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) { 766193149Sdougb /* Yup. This is a hack */ 767193149Sdougb result = dns_name_concatenate(keyname, dns_rootname, 768193149Sdougb keyname, NULL); 769193149Sdougb if (result != ISC_R_SUCCESS) 770193149Sdougb goto failure; 771193149Sdougb } else { 772193149Sdougb result = dns_name_concatenate(keyname, tctx->domain, 773193149Sdougb keyname, NULL); 774193149Sdougb if (result != ISC_R_SUCCESS) 775193149Sdougb goto failure; 776193149Sdougb } 777193149Sdougb 778135446Strhodes result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring); 779193149Sdougb 780135446Strhodes if (result == ISC_R_SUCCESS) { 781135446Strhodes tkeyout.error = dns_tsigerror_badname; 782135446Strhodes dns_tsigkey_detach(&tsigkey); 783135446Strhodes goto failure_with_tkey; 784135446Strhodes } else if (result != ISC_R_NOTFOUND) 785135446Strhodes goto failure; 786135446Strhodes } else 787135446Strhodes keyname = qname; 788135446Strhodes 789135446Strhodes switch (tkeyin.mode) { 790135446Strhodes case DNS_TKEYMODE_DIFFIEHELLMAN: 791135446Strhodes tkeyout.error = dns_rcode_noerror; 792135446Strhodes RETERR(process_dhtkey(msg, signer, keyname, &tkeyin, 793135446Strhodes tctx, &tkeyout, ring, 794135446Strhodes &namelist)); 795135446Strhodes break; 796135446Strhodes case DNS_TKEYMODE_GSSAPI: 797135446Strhodes tkeyout.error = dns_rcode_noerror; 798218384Sdougb RETERR(process_gsstkey(keyname, &tkeyin, tctx, 799218384Sdougb &tkeyout, ring)); 800135446Strhodes break; 801135446Strhodes case DNS_TKEYMODE_DELETE: 802135446Strhodes tkeyout.error = dns_rcode_noerror; 803218384Sdougb RETERR(process_deletetkey(signer, keyname, &tkeyin, 804218384Sdougb &tkeyout, ring)); 805135446Strhodes break; 806135446Strhodes case DNS_TKEYMODE_SERVERASSIGNED: 807135446Strhodes case DNS_TKEYMODE_RESOLVERASSIGNED: 808135446Strhodes result = DNS_R_NOTIMP; 809135446Strhodes goto failure; 810135446Strhodes default: 811135446Strhodes tkeyout.error = dns_tsigerror_badmode; 812135446Strhodes } 813135446Strhodes 814135446Strhodes failure_with_tkey: 815135446Strhodes dns_rdata_init(&rdata); 816135446Strhodes isc_buffer_init(&tkeyoutbuf, tkeyoutdata, sizeof(tkeyoutdata)); 817135446Strhodes result = dns_rdata_fromstruct(&rdata, tkeyout.common.rdclass, 818135446Strhodes tkeyout.common.rdtype, &tkeyout, 819135446Strhodes &tkeyoutbuf); 820135446Strhodes 821135446Strhodes if (freetkeyin) { 822135446Strhodes dns_rdata_freestruct(&tkeyin); 823135446Strhodes freetkeyin = ISC_FALSE; 824135446Strhodes } 825135446Strhodes 826135446Strhodes if (tkeyout.key != NULL) 827193149Sdougb isc_mem_put(tkeyout.mctx, tkeyout.key, tkeyout.keylen); 828135446Strhodes if (tkeyout.other != NULL) 829193149Sdougb isc_mem_put(tkeyout.mctx, tkeyout.other, tkeyout.otherlen); 830135446Strhodes if (result != ISC_R_SUCCESS) 831135446Strhodes goto failure; 832135446Strhodes 833135446Strhodes RETERR(add_rdata_to_list(msg, keyname, &rdata, 0, &namelist)); 834135446Strhodes 835135446Strhodes RETERR(dns_message_reply(msg, ISC_TRUE)); 836135446Strhodes 837135446Strhodes name = ISC_LIST_HEAD(namelist); 838135446Strhodes while (name != NULL) { 839135446Strhodes dns_name_t *next = ISC_LIST_NEXT(name, link); 840135446Strhodes ISC_LIST_UNLINK(namelist, name, link); 841135446Strhodes dns_message_addname(msg, name, DNS_SECTION_ANSWER); 842135446Strhodes name = next; 843135446Strhodes } 844135446Strhodes 845135446Strhodes return (ISC_R_SUCCESS); 846135446Strhodes 847135446Strhodes failure: 848135446Strhodes if (freetkeyin) 849135446Strhodes dns_rdata_freestruct(&tkeyin); 850135446Strhodes if (!ISC_LIST_EMPTY(namelist)) 851135446Strhodes free_namelist(msg, &namelist); 852135446Strhodes return (result); 853135446Strhodes} 854135446Strhodes 855135446Strhodesstatic isc_result_t 856135446Strhodesbuildquery(dns_message_t *msg, dns_name_t *name, 857193149Sdougb dns_rdata_tkey_t *tkey, isc_boolean_t win2k) 858135446Strhodes{ 859135446Strhodes dns_name_t *qname = NULL, *aname = NULL; 860135446Strhodes dns_rdataset_t *question = NULL, *tkeyset = NULL; 861135446Strhodes dns_rdatalist_t *tkeylist = NULL; 862135446Strhodes dns_rdata_t *rdata = NULL; 863135446Strhodes isc_buffer_t *dynbuf = NULL; 864135446Strhodes isc_result_t result; 865135446Strhodes 866135446Strhodes REQUIRE(msg != NULL); 867135446Strhodes REQUIRE(name != NULL); 868135446Strhodes REQUIRE(tkey != NULL); 869135446Strhodes 870135446Strhodes RETERR(dns_message_gettempname(msg, &qname)); 871135446Strhodes RETERR(dns_message_gettempname(msg, &aname)); 872135446Strhodes 873135446Strhodes RETERR(dns_message_gettemprdataset(msg, &question)); 874135446Strhodes dns_rdataset_init(question); 875135446Strhodes dns_rdataset_makequestion(question, dns_rdataclass_any, 876135446Strhodes dns_rdatatype_tkey); 877135446Strhodes 878193149Sdougb RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 4096)); 879135446Strhodes RETERR(dns_message_gettemprdata(msg, &rdata)); 880193149Sdougb 881135446Strhodes RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any, 882135446Strhodes dns_rdatatype_tkey, tkey, dynbuf)); 883135446Strhodes dns_message_takebuffer(msg, &dynbuf); 884135446Strhodes 885135446Strhodes RETERR(dns_message_gettemprdatalist(msg, &tkeylist)); 886135446Strhodes tkeylist->rdclass = dns_rdataclass_any; 887135446Strhodes tkeylist->type = dns_rdatatype_tkey; 888135446Strhodes tkeylist->covers = 0; 889135446Strhodes tkeylist->ttl = 0; 890135446Strhodes ISC_LIST_INIT(tkeylist->rdata); 891135446Strhodes ISC_LIST_APPEND(tkeylist->rdata, rdata, link); 892135446Strhodes 893135446Strhodes RETERR(dns_message_gettemprdataset(msg, &tkeyset)); 894135446Strhodes dns_rdataset_init(tkeyset); 895135446Strhodes RETERR(dns_rdatalist_tordataset(tkeylist, tkeyset)); 896135446Strhodes 897135446Strhodes dns_name_init(qname, NULL); 898135446Strhodes dns_name_clone(name, qname); 899135446Strhodes 900135446Strhodes dns_name_init(aname, NULL); 901135446Strhodes dns_name_clone(name, aname); 902135446Strhodes 903135446Strhodes ISC_LIST_APPEND(qname->list, question, link); 904135446Strhodes ISC_LIST_APPEND(aname->list, tkeyset, link); 905135446Strhodes 906135446Strhodes dns_message_addname(msg, qname, DNS_SECTION_QUESTION); 907135446Strhodes 908193149Sdougb /* 909193149Sdougb * Windows 2000 needs this in the answer section, not the additional 910193149Sdougb * section where the RFC specifies. 911193149Sdougb */ 912193149Sdougb if (win2k) 913193149Sdougb dns_message_addname(msg, aname, DNS_SECTION_ANSWER); 914193149Sdougb else 915193149Sdougb dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL); 916193149Sdougb 917135446Strhodes return (ISC_R_SUCCESS); 918135446Strhodes 919135446Strhodes failure: 920135446Strhodes if (qname != NULL) 921135446Strhodes dns_message_puttempname(msg, &qname); 922135446Strhodes if (aname != NULL) 923135446Strhodes dns_message_puttempname(msg, &aname); 924135446Strhodes if (question != NULL) { 925135446Strhodes dns_rdataset_disassociate(question); 926135446Strhodes dns_message_puttemprdataset(msg, &question); 927135446Strhodes } 928135446Strhodes if (dynbuf != NULL) 929135446Strhodes isc_buffer_free(&dynbuf); 930193149Sdougb printf("buildquery error\n"); 931135446Strhodes return (result); 932135446Strhodes} 933135446Strhodes 934135446Strhodesisc_result_t 935135446Strhodesdns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, 936135446Strhodes dns_name_t *algorithm, isc_buffer_t *nonce, 937135446Strhodes isc_uint32_t lifetime) 938135446Strhodes{ 939135446Strhodes dns_rdata_tkey_t tkey; 940135446Strhodes dns_rdata_t *rdata = NULL; 941135446Strhodes isc_buffer_t *dynbuf = NULL; 942135446Strhodes isc_region_t r; 943135446Strhodes dns_name_t keyname; 944135446Strhodes dns_namelist_t namelist; 945135446Strhodes isc_result_t result; 946135446Strhodes isc_stdtime_t now; 947135446Strhodes 948135446Strhodes REQUIRE(msg != NULL); 949135446Strhodes REQUIRE(key != NULL); 950135446Strhodes REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 951135446Strhodes REQUIRE(dst_key_isprivate(key)); 952135446Strhodes REQUIRE(name != NULL); 953135446Strhodes REQUIRE(algorithm != NULL); 954135446Strhodes 955135446Strhodes tkey.common.rdclass = dns_rdataclass_any; 956135446Strhodes tkey.common.rdtype = dns_rdatatype_tkey; 957135446Strhodes ISC_LINK_INIT(&tkey.common, link); 958135446Strhodes tkey.mctx = msg->mctx; 959135446Strhodes dns_name_init(&tkey.algorithm, NULL); 960135446Strhodes dns_name_clone(algorithm, &tkey.algorithm); 961135446Strhodes isc_stdtime_get(&now); 962135446Strhodes tkey.inception = now; 963135446Strhodes tkey.expire = now + lifetime; 964135446Strhodes tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN; 965135446Strhodes if (nonce != NULL) 966135446Strhodes isc_buffer_usedregion(nonce, &r); 967135446Strhodes else { 968135446Strhodes r.base = isc_mem_get(msg->mctx, 0); 969135446Strhodes r.length = 0; 970135446Strhodes } 971135446Strhodes tkey.error = 0; 972135446Strhodes tkey.key = r.base; 973135446Strhodes tkey.keylen = r.length; 974135446Strhodes tkey.other = NULL; 975135446Strhodes tkey.otherlen = 0; 976135446Strhodes 977193149Sdougb RETERR(buildquery(msg, name, &tkey, ISC_FALSE)); 978135446Strhodes 979135446Strhodes if (nonce == NULL) 980135446Strhodes isc_mem_put(msg->mctx, r.base, 0); 981135446Strhodes 982135446Strhodes RETERR(dns_message_gettemprdata(msg, &rdata)); 983135446Strhodes RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024)); 984135446Strhodes RETERR(dst_key_todns(key, dynbuf)); 985135446Strhodes isc_buffer_usedregion(dynbuf, &r); 986135446Strhodes dns_rdata_fromregion(rdata, dns_rdataclass_any, 987135446Strhodes dns_rdatatype_key, &r); 988135446Strhodes dns_message_takebuffer(msg, &dynbuf); 989135446Strhodes 990135446Strhodes dns_name_init(&keyname, NULL); 991135446Strhodes dns_name_clone(dst_key_name(key), &keyname); 992135446Strhodes 993135446Strhodes ISC_LIST_INIT(namelist); 994135446Strhodes RETERR(add_rdata_to_list(msg, &keyname, rdata, 0, &namelist)); 995254402Serwin name = ISC_LIST_HEAD(namelist); 996254402Serwin while (name != NULL) { 997254402Serwin dns_name_t *next = ISC_LIST_NEXT(name, link); 998254402Serwin ISC_LIST_UNLINK(namelist, name, link); 999254402Serwin dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL); 1000254402Serwin name = next; 1001254402Serwin } 1002135446Strhodes 1003135446Strhodes return (ISC_R_SUCCESS); 1004135446Strhodes 1005135446Strhodes failure: 1006135446Strhodes 1007135446Strhodes if (dynbuf != NULL) 1008135446Strhodes isc_buffer_free(&dynbuf); 1009135446Strhodes return (result); 1010135446Strhodes} 1011135446Strhodes 1012135446Strhodesisc_result_t 1013193149Sdougbdns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, 1014193149Sdougb isc_buffer_t *intoken, isc_uint32_t lifetime, 1015224092Sdougb gss_ctx_id_t *context, isc_boolean_t win2k, 1016224092Sdougb isc_mem_t *mctx, char **err_message) 1017135446Strhodes{ 1018135446Strhodes dns_rdata_tkey_t tkey; 1019135446Strhodes isc_result_t result; 1020135446Strhodes isc_stdtime_t now; 1021135446Strhodes isc_buffer_t token; 1022193149Sdougb unsigned char array[4096]; 1023135446Strhodes 1024193149Sdougb UNUSED(intoken); 1025193149Sdougb 1026135446Strhodes REQUIRE(msg != NULL); 1027135446Strhodes REQUIRE(name != NULL); 1028135446Strhodes REQUIRE(gname != NULL); 1029193149Sdougb REQUIRE(context != NULL); 1030224092Sdougb REQUIRE(mctx != NULL); 1031135446Strhodes 1032135446Strhodes isc_buffer_init(&token, array, sizeof(array)); 1033224092Sdougb result = dst_gssapi_initctx(gname, NULL, &token, context, 1034224092Sdougb mctx, err_message); 1035135446Strhodes if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) 1036135446Strhodes return (result); 1037135446Strhodes 1038135446Strhodes tkey.common.rdclass = dns_rdataclass_any; 1039135446Strhodes tkey.common.rdtype = dns_rdatatype_tkey; 1040135446Strhodes ISC_LINK_INIT(&tkey.common, link); 1041135446Strhodes tkey.mctx = NULL; 1042135446Strhodes dns_name_init(&tkey.algorithm, NULL); 1043193149Sdougb 1044193149Sdougb if (win2k) 1045193149Sdougb dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); 1046193149Sdougb else 1047193149Sdougb dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); 1048193149Sdougb 1049135446Strhodes isc_stdtime_get(&now); 1050135446Strhodes tkey.inception = now; 1051135446Strhodes tkey.expire = now + lifetime; 1052135446Strhodes tkey.mode = DNS_TKEYMODE_GSSAPI; 1053135446Strhodes tkey.error = 0; 1054135446Strhodes tkey.key = isc_buffer_base(&token); 1055135446Strhodes tkey.keylen = isc_buffer_usedlength(&token); 1056135446Strhodes tkey.other = NULL; 1057135446Strhodes tkey.otherlen = 0; 1058135446Strhodes 1059193149Sdougb RETERR(buildquery(msg, name, &tkey, win2k)); 1060135446Strhodes 1061135446Strhodes return (ISC_R_SUCCESS); 1062135446Strhodes 1063135446Strhodes failure: 1064135446Strhodes return (result); 1065135446Strhodes} 1066135446Strhodes 1067135446Strhodesisc_result_t 1068135446Strhodesdns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) { 1069135446Strhodes dns_rdata_tkey_t tkey; 1070135446Strhodes 1071135446Strhodes REQUIRE(msg != NULL); 1072135446Strhodes REQUIRE(key != NULL); 1073135446Strhodes 1074135446Strhodes tkey.common.rdclass = dns_rdataclass_any; 1075135446Strhodes tkey.common.rdtype = dns_rdatatype_tkey; 1076135446Strhodes ISC_LINK_INIT(&tkey.common, link); 1077135446Strhodes tkey.mctx = msg->mctx; 1078135446Strhodes dns_name_init(&tkey.algorithm, NULL); 1079135446Strhodes dns_name_clone(key->algorithm, &tkey.algorithm); 1080135446Strhodes tkey.inception = tkey.expire = 0; 1081135446Strhodes tkey.mode = DNS_TKEYMODE_DELETE; 1082135446Strhodes tkey.error = 0; 1083135446Strhodes tkey.keylen = tkey.otherlen = 0; 1084135446Strhodes tkey.key = tkey.other = NULL; 1085135446Strhodes 1086193149Sdougb return (buildquery(msg, &key->name, &tkey, ISC_FALSE)); 1087135446Strhodes} 1088135446Strhodes 1089135446Strhodesstatic isc_result_t 1090135446Strhodesfind_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata, 1091135446Strhodes int section) 1092135446Strhodes{ 1093135446Strhodes dns_rdataset_t *tkeyset; 1094135446Strhodes isc_result_t result; 1095135446Strhodes 1096135446Strhodes result = dns_message_firstname(msg, section); 1097135446Strhodes while (result == ISC_R_SUCCESS) { 1098135446Strhodes *name = NULL; 1099135446Strhodes dns_message_currentname(msg, section, name); 1100135446Strhodes tkeyset = NULL; 1101135446Strhodes result = dns_message_findtype(*name, dns_rdatatype_tkey, 0, 1102135446Strhodes &tkeyset); 1103135446Strhodes if (result == ISC_R_SUCCESS) { 1104135446Strhodes result = dns_rdataset_first(tkeyset); 1105135446Strhodes if (result != ISC_R_SUCCESS) 1106135446Strhodes return (result); 1107135446Strhodes dns_rdataset_current(tkeyset, rdata); 1108135446Strhodes return (ISC_R_SUCCESS); 1109135446Strhodes } 1110135446Strhodes result = dns_message_nextname(msg, section); 1111135446Strhodes } 1112135446Strhodes if (result == ISC_R_NOMORE) 1113135446Strhodes return (ISC_R_NOTFOUND); 1114135446Strhodes return (result); 1115135446Strhodes} 1116135446Strhodes 1117135446Strhodesisc_result_t 1118135446Strhodesdns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1119135446Strhodes dst_key_t *key, isc_buffer_t *nonce, 1120135446Strhodes dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring) 1121135446Strhodes{ 1122135446Strhodes dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1123135446Strhodes dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname; 1124135446Strhodes dns_rdataset_t *theirkeyset = NULL, *ourkeyset = NULL; 1125135446Strhodes dns_rdata_t theirkeyrdata = DNS_RDATA_INIT; 1126135446Strhodes dst_key_t *theirkey = NULL; 1127135446Strhodes dns_rdata_tkey_t qtkey, rtkey; 1128135446Strhodes unsigned char secretdata[256]; 1129135446Strhodes unsigned int sharedsize; 1130135446Strhodes isc_buffer_t *shared = NULL, secret; 1131135446Strhodes isc_region_t r, r2; 1132135446Strhodes isc_result_t result; 1133135446Strhodes isc_boolean_t freertkey = ISC_FALSE; 1134135446Strhodes 1135135446Strhodes REQUIRE(qmsg != NULL); 1136135446Strhodes REQUIRE(rmsg != NULL); 1137135446Strhodes REQUIRE(key != NULL); 1138135446Strhodes REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH); 1139135446Strhodes REQUIRE(dst_key_isprivate(key)); 1140135446Strhodes if (outkey != NULL) 1141135446Strhodes REQUIRE(*outkey == NULL); 1142135446Strhodes 1143135446Strhodes if (rmsg->rcode != dns_rcode_noerror) 1144135446Strhodes return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1145135446Strhodes RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1146135446Strhodes RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1147135446Strhodes freertkey = ISC_TRUE; 1148135446Strhodes 1149135446Strhodes RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, 1150135446Strhodes DNS_SECTION_ADDITIONAL)); 1151135446Strhodes RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1152135446Strhodes 1153135446Strhodes if (rtkey.error != dns_rcode_noerror || 1154135446Strhodes rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN || 1155135446Strhodes rtkey.mode != qtkey.mode || 1156135446Strhodes !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1157193149Sdougb rmsg->rcode != dns_rcode_noerror) { 1158135446Strhodes tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1159193149Sdougb "or error set(1)"); 1160135446Strhodes result = DNS_R_INVALIDTKEY; 1161135446Strhodes dns_rdata_freestruct(&qtkey); 1162135446Strhodes goto failure; 1163135446Strhodes } 1164135446Strhodes 1165135446Strhodes dns_rdata_freestruct(&qtkey); 1166135446Strhodes 1167135446Strhodes dns_name_init(&keyname, NULL); 1168135446Strhodes dns_name_clone(dst_key_name(key), &keyname); 1169135446Strhodes 1170135446Strhodes ourkeyname = NULL; 1171135446Strhodes ourkeyset = NULL; 1172135446Strhodes RETERR(dns_message_findname(rmsg, DNS_SECTION_ANSWER, &keyname, 1173135446Strhodes dns_rdatatype_key, 0, &ourkeyname, 1174135446Strhodes &ourkeyset)); 1175135446Strhodes 1176135446Strhodes result = dns_message_firstname(rmsg, DNS_SECTION_ANSWER); 1177135446Strhodes while (result == ISC_R_SUCCESS) { 1178135446Strhodes theirkeyname = NULL; 1179135446Strhodes dns_message_currentname(rmsg, DNS_SECTION_ANSWER, 1180135446Strhodes &theirkeyname); 1181135446Strhodes if (dns_name_equal(theirkeyname, ourkeyname)) 1182135446Strhodes goto next; 1183135446Strhodes theirkeyset = NULL; 1184135446Strhodes result = dns_message_findtype(theirkeyname, dns_rdatatype_key, 1185135446Strhodes 0, &theirkeyset); 1186135446Strhodes if (result == ISC_R_SUCCESS) { 1187135446Strhodes RETERR(dns_rdataset_first(theirkeyset)); 1188135446Strhodes break; 1189135446Strhodes } 1190135446Strhodes next: 1191135446Strhodes result = dns_message_nextname(rmsg, DNS_SECTION_ANSWER); 1192135446Strhodes } 1193135446Strhodes 1194135446Strhodes if (theirkeyset == NULL) { 1195135446Strhodes tkey_log("dns_tkey_processdhresponse: failed to find server " 1196135446Strhodes "key"); 1197135446Strhodes result = ISC_R_NOTFOUND; 1198135446Strhodes goto failure; 1199135446Strhodes } 1200135446Strhodes 1201135446Strhodes dns_rdataset_current(theirkeyset, &theirkeyrdata); 1202135446Strhodes RETERR(dns_dnssec_keyfromrdata(theirkeyname, &theirkeyrdata, 1203135446Strhodes rmsg->mctx, &theirkey)); 1204135446Strhodes 1205135446Strhodes RETERR(dst_key_secretsize(key, &sharedsize)); 1206135446Strhodes RETERR(isc_buffer_allocate(rmsg->mctx, &shared, sharedsize)); 1207135446Strhodes 1208135446Strhodes RETERR(dst_key_computesecret(theirkey, key, shared)); 1209135446Strhodes 1210135446Strhodes isc_buffer_init(&secret, secretdata, sizeof(secretdata)); 1211135446Strhodes 1212135446Strhodes r.base = rtkey.key; 1213135446Strhodes r.length = rtkey.keylen; 1214135446Strhodes if (nonce != NULL) 1215135446Strhodes isc_buffer_usedregion(nonce, &r2); 1216135446Strhodes else { 1217135446Strhodes r2.base = isc_mem_get(rmsg->mctx, 0); 1218135446Strhodes r2.length = 0; 1219135446Strhodes } 1220135446Strhodes RETERR(compute_secret(shared, &r2, &r, &secret)); 1221135446Strhodes if (nonce == NULL) 1222135446Strhodes isc_mem_put(rmsg->mctx, r2.base, 0); 1223135446Strhodes 1224135446Strhodes isc_buffer_usedregion(&secret, &r); 1225135446Strhodes result = dns_tsigkey_create(tkeyname, &rtkey.algorithm, 1226135446Strhodes r.base, r.length, ISC_TRUE, 1227135446Strhodes NULL, rtkey.inception, rtkey.expire, 1228193149Sdougb rmsg->mctx, ring, outkey); 1229135446Strhodes isc_buffer_free(&shared); 1230135446Strhodes dns_rdata_freestruct(&rtkey); 1231135446Strhodes dst_key_free(&theirkey); 1232135446Strhodes return (result); 1233135446Strhodes 1234135446Strhodes failure: 1235135446Strhodes if (shared != NULL) 1236135446Strhodes isc_buffer_free(&shared); 1237135446Strhodes 1238135446Strhodes if (theirkey != NULL) 1239135446Strhodes dst_key_free(&theirkey); 1240135446Strhodes 1241135446Strhodes if (freertkey) 1242135446Strhodes dns_rdata_freestruct(&rtkey); 1243135446Strhodes 1244135446Strhodes return (result); 1245135446Strhodes} 1246135446Strhodes 1247135446Strhodesisc_result_t 1248135446Strhodesdns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1249193149Sdougb dns_name_t *gname, gss_ctx_id_t *context, 1250193149Sdougb isc_buffer_t *outtoken, dns_tsigkey_t **outkey, 1251224092Sdougb dns_tsig_keyring_t *ring, char **err_message) 1252135446Strhodes{ 1253135446Strhodes dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1254135446Strhodes dns_name_t *tkeyname; 1255135446Strhodes dns_rdata_tkey_t rtkey, qtkey; 1256135446Strhodes dst_key_t *dstkey = NULL; 1257193149Sdougb isc_buffer_t intoken; 1258135446Strhodes isc_result_t result; 1259135446Strhodes unsigned char array[1024]; 1260135446Strhodes 1261193149Sdougb REQUIRE(outtoken != NULL); 1262135446Strhodes REQUIRE(qmsg != NULL); 1263135446Strhodes REQUIRE(rmsg != NULL); 1264135446Strhodes REQUIRE(gname != NULL); 1265224092Sdougb REQUIRE(ring != NULL); 1266135446Strhodes if (outkey != NULL) 1267135446Strhodes REQUIRE(*outkey == NULL); 1268135446Strhodes 1269135446Strhodes if (rmsg->rcode != dns_rcode_noerror) 1270135446Strhodes return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1271135446Strhodes RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1272135446Strhodes RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1273135446Strhodes 1274193149Sdougb /* 1275193149Sdougb * Win2k puts the item in the ANSWER section, while the RFC 1276193149Sdougb * specifies it should be in the ADDITIONAL section. Check first 1277193149Sdougb * where it should be, and then where it may be. 1278193149Sdougb */ 1279193149Sdougb result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1280193149Sdougb DNS_SECTION_ADDITIONAL); 1281193149Sdougb if (result == ISC_R_NOTFOUND) 1282193149Sdougb result = find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1283193149Sdougb DNS_SECTION_ANSWER); 1284193149Sdougb if (result != ISC_R_SUCCESS) 1285193149Sdougb goto failure; 1286193149Sdougb 1287135446Strhodes RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1288135446Strhodes 1289135446Strhodes if (rtkey.error != dns_rcode_noerror || 1290135446Strhodes rtkey.mode != DNS_TKEYMODE_GSSAPI || 1291193149Sdougb !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) { 1292193149Sdougb tkey_log("dns_tkey_processgssresponse: tkey mode invalid " 1293193149Sdougb "or error set(2) %d", rtkey.error); 1294193149Sdougb _dns_tkey_dumpmessage(qmsg); 1295193149Sdougb _dns_tkey_dumpmessage(rmsg); 1296135446Strhodes result = DNS_R_INVALIDTKEY; 1297135446Strhodes goto failure; 1298135446Strhodes } 1299135446Strhodes 1300193149Sdougb isc_buffer_init(outtoken, array, sizeof(array)); 1301193149Sdougb isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1302224092Sdougb RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context, 1303224092Sdougb ring->mctx, err_message)); 1304135446Strhodes 1305135446Strhodes RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, 1306224092Sdougb &dstkey, NULL)); 1307135446Strhodes 1308135446Strhodes RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME, 1309193149Sdougb dstkey, ISC_FALSE, NULL, 1310135446Strhodes rtkey.inception, rtkey.expire, 1311186462Sdougb ring->mctx, ring, outkey)); 1312218384Sdougb dst_key_free(&dstkey); 1313135446Strhodes dns_rdata_freestruct(&rtkey); 1314135446Strhodes return (result); 1315135446Strhodes 1316135446Strhodes failure: 1317193149Sdougb /* 1318193149Sdougb * XXXSRA This probably leaks memory from rtkey and qtkey. 1319193149Sdougb */ 1320218384Sdougb if (dstkey != NULL) 1321218384Sdougb dst_key_free(&dstkey); 1322135446Strhodes return (result); 1323135446Strhodes} 1324135446Strhodes 1325135446Strhodesisc_result_t 1326135446Strhodesdns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, 1327135446Strhodes dns_tsig_keyring_t *ring) 1328135446Strhodes{ 1329135446Strhodes dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT; 1330135446Strhodes dns_name_t *tkeyname, *tempname; 1331135446Strhodes dns_rdata_tkey_t qtkey, rtkey; 1332135446Strhodes dns_tsigkey_t *tsigkey = NULL; 1333135446Strhodes isc_result_t result; 1334135446Strhodes 1335135446Strhodes REQUIRE(qmsg != NULL); 1336135446Strhodes REQUIRE(rmsg != NULL); 1337135446Strhodes 1338135446Strhodes if (rmsg->rcode != dns_rcode_noerror) 1339135446Strhodes return(ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1340135446Strhodes 1341135446Strhodes RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1342135446Strhodes RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1343135446Strhodes 1344135446Strhodes RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata, 1345135446Strhodes DNS_SECTION_ADDITIONAL)); 1346135446Strhodes RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1347135446Strhodes 1348135446Strhodes if (rtkey.error != dns_rcode_noerror || 1349135446Strhodes rtkey.mode != DNS_TKEYMODE_DELETE || 1350135446Strhodes rtkey.mode != qtkey.mode || 1351135446Strhodes !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) || 1352193149Sdougb rmsg->rcode != dns_rcode_noerror) { 1353135446Strhodes tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid " 1354193149Sdougb "or error set(3)"); 1355135446Strhodes result = DNS_R_INVALIDTKEY; 1356135446Strhodes dns_rdata_freestruct(&qtkey); 1357135446Strhodes dns_rdata_freestruct(&rtkey); 1358135446Strhodes goto failure; 1359135446Strhodes } 1360135446Strhodes 1361135446Strhodes dns_rdata_freestruct(&qtkey); 1362135446Strhodes 1363135446Strhodes RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm, ring)); 1364135446Strhodes 1365135446Strhodes dns_rdata_freestruct(&rtkey); 1366135446Strhodes 1367135446Strhodes /* 1368135446Strhodes * Mark the key as deleted. 1369135446Strhodes */ 1370135446Strhodes dns_tsigkey_setdeleted(tsigkey); 1371135446Strhodes /* 1372135446Strhodes * Release the reference. 1373135446Strhodes */ 1374135446Strhodes dns_tsigkey_detach(&tsigkey); 1375135446Strhodes 1376135446Strhodes failure: 1377135446Strhodes return (result); 1378135446Strhodes} 1379193149Sdougb 1380193149Sdougbisc_result_t 1381193149Sdougbdns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, 1382193149Sdougb dns_name_t *server, gss_ctx_id_t *context, 1383193149Sdougb dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, 1384224092Sdougb isc_boolean_t win2k, char **err_message) 1385193149Sdougb{ 1386193149Sdougb dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; 1387193149Sdougb dns_name_t *tkeyname; 1388193149Sdougb dns_rdata_tkey_t rtkey, qtkey; 1389193149Sdougb isc_buffer_t intoken, outtoken; 1390193149Sdougb dst_key_t *dstkey = NULL; 1391193149Sdougb isc_result_t result; 1392193149Sdougb unsigned char array[1024]; 1393193149Sdougb 1394193149Sdougb REQUIRE(qmsg != NULL); 1395193149Sdougb REQUIRE(rmsg != NULL); 1396193149Sdougb REQUIRE(server != NULL); 1397193149Sdougb if (outkey != NULL) 1398193149Sdougb REQUIRE(*outkey == NULL); 1399193149Sdougb 1400193149Sdougb if (rmsg->rcode != dns_rcode_noerror) 1401193149Sdougb return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode); 1402193149Sdougb 1403193149Sdougb RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER)); 1404193149Sdougb RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL)); 1405193149Sdougb 1406193149Sdougb if (win2k == ISC_TRUE) 1407193149Sdougb RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1408218384Sdougb DNS_SECTION_ANSWER)); 1409193149Sdougb else 1410193149Sdougb RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata, 1411218384Sdougb DNS_SECTION_ADDITIONAL)); 1412193149Sdougb 1413193149Sdougb RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL)); 1414193149Sdougb 1415193149Sdougb if (rtkey.error != dns_rcode_noerror || 1416193149Sdougb rtkey.mode != DNS_TKEYMODE_GSSAPI || 1417193149Sdougb !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) 1418193149Sdougb { 1419193149Sdougb tkey_log("dns_tkey_processdhresponse: tkey mode invalid " 1420193149Sdougb "or error set(4)"); 1421193149Sdougb result = DNS_R_INVALIDTKEY; 1422193149Sdougb goto failure; 1423193149Sdougb } 1424193149Sdougb 1425193149Sdougb isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); 1426193149Sdougb isc_buffer_init(&outtoken, array, sizeof(array)); 1427193149Sdougb 1428224092Sdougb result = dst_gssapi_initctx(server, &intoken, &outtoken, context, 1429224092Sdougb ring->mctx, err_message); 1430193149Sdougb if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) 1431193149Sdougb return (result); 1432193149Sdougb 1433193149Sdougb RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, 1434224092Sdougb &dstkey, NULL)); 1435193149Sdougb 1436193149Sdougb /* 1437193149Sdougb * XXXSRA This seems confused. If we got CONTINUE from initctx, 1438193149Sdougb * the GSS negotiation hasn't completed yet, so we can't sign 1439193149Sdougb * anything yet. 1440193149Sdougb */ 1441193149Sdougb 1442193149Sdougb RETERR(dns_tsigkey_createfromkey(tkeyname, 1443193149Sdougb (win2k 1444193149Sdougb ? DNS_TSIG_GSSAPIMS_NAME 1445193149Sdougb : DNS_TSIG_GSSAPI_NAME), 1446193149Sdougb dstkey, ISC_TRUE, NULL, 1447193149Sdougb rtkey.inception, rtkey.expire, 1448193149Sdougb ring->mctx, ring, outkey)); 1449218384Sdougb dst_key_free(&dstkey); 1450193149Sdougb dns_rdata_freestruct(&rtkey); 1451193149Sdougb return (result); 1452193149Sdougb 1453193149Sdougb failure: 1454193149Sdougb /* 1455193149Sdougb * XXXSRA This probably leaks memory from qtkey. 1456193149Sdougb */ 1457193149Sdougb dns_rdata_freestruct(&rtkey); 1458218384Sdougb if (dstkey != NULL) 1459218384Sdougb dst_key_free(&dstkey); 1460193149Sdougb return (result); 1461193149Sdougb} 1462