"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/tkey.c" (4 Sep 2020, 42196 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tkey.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.17.1_vs_9.17.2.

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