[BACK]Return to tkey.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / mpl / bind / dist / lib / dns

Annotation of src/external/mpl/bind/dist/lib/dns/tkey.c, Revision 1.1.1.7

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

CVSweb <webmaster@jp.NetBSD.org>