tkey.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*
00019  * $Id$
00020  */
00021 /*! \file */
00022 #include <config.h>
00023 
00024 #include <isc/buffer.h>
00025 #include <isc/entropy.h>
00026 #include <isc/md5.h>
00027 #include <isc/mem.h>
00028 #include <isc/string.h>
00029 #include <isc/util.h>
00030 
00031 #include <dns/dnssec.h>
00032 #include <dns/fixedname.h>
00033 #include <dns/keyvalues.h>
00034 #include <dns/log.h>
00035 #include <dns/message.h>
00036 #include <dns/name.h>
00037 #include <dns/rdata.h>
00038 #include <dns/rdatalist.h>
00039 #include <dns/rdataset.h>
00040 #include <dns/rdatastruct.h>
00041 #include <dns/result.h>
00042 #include <dns/tkey.h>
00043 #include <dns/tsig.h>
00044 
00045 #include <dst/dst.h>
00046 #include <dst/gssapi.h>
00047 
00048 #include "dst_internal.h"
00049 
00050 #define TKEY_RANDOM_AMOUNT 16
00051 
00052 #ifdef PKCS11CRYPTO
00053 #include <pk11/pk11.h>
00054 #endif
00055 
00056 #define RETERR(x) do { \
00057         result = (x); \
00058         if (result != ISC_R_SUCCESS) \
00059                 goto failure; \
00060         } while (0)
00061 
00062 static void
00063 tkey_log(const char *fmt, ...) ISC_FORMAT_PRINTF(1, 2);
00064 
00065 static void
00066 tkey_log(const char *fmt, ...) {
00067         va_list ap;
00068 
00069         va_start(ap, fmt);
00070         isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
00071                        DNS_LOGMODULE_REQUEST, ISC_LOG_DEBUG(4), fmt, ap);
00072         va_end(ap);
00073 }
00074 
00075 static void
00076 _dns_tkey_dumpmessage(dns_message_t *msg) {
00077         isc_buffer_t outbuf;
00078         unsigned char output[4096];
00079         isc_result_t result;
00080 
00081         isc_buffer_init(&outbuf, output, sizeof(output));
00082         result = dns_message_totext(msg, &dns_master_style_debug, 0,
00083                                     &outbuf);
00084         if (result != ISC_R_SUCCESS)
00085                 fprintf(stderr, "Warning: dns_message_totext returned: %s\n",
00086                         dns_result_totext(result));
00087         fprintf(stderr, "%.*s\n", (int)isc_buffer_usedlength(&outbuf),
00088                 (char *)isc_buffer_base(&outbuf));
00089 }
00090 
00091 isc_result_t
00092 dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp)
00093 {
00094         dns_tkeyctx_t *tctx;
00095 
00096         REQUIRE(mctx != NULL);
00097         REQUIRE(ectx != NULL);
00098         REQUIRE(tctxp != NULL && *tctxp == NULL);
00099 
00100         tctx = isc_mem_get(mctx, sizeof(dns_tkeyctx_t));
00101         if (tctx == NULL)
00102                 return (ISC_R_NOMEMORY);
00103         tctx->mctx = NULL;
00104         isc_mem_attach(mctx, &tctx->mctx);
00105         tctx->ectx = NULL;
00106         isc_entropy_attach(ectx, &tctx->ectx);
00107         tctx->dhkey = NULL;
00108         tctx->domain = NULL;
00109         tctx->gsscred = NULL;
00110         tctx->gssapi_keytab = NULL;
00111 
00112         *tctxp = tctx;
00113         return (ISC_R_SUCCESS);
00114 }
00115 
00116 void
00117 dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp) {
00118         isc_mem_t *mctx;
00119         dns_tkeyctx_t *tctx;
00120 
00121         REQUIRE(tctxp != NULL && *tctxp != NULL);
00122 
00123         tctx = *tctxp;
00124         mctx = tctx->mctx;
00125 
00126         if (tctx->dhkey != NULL)
00127                 dst_key_free(&tctx->dhkey);
00128         if (tctx->domain != NULL) {
00129                 if (dns_name_dynamic(tctx->domain))
00130                         dns_name_free(tctx->domain, mctx);
00131                 isc_mem_put(mctx, tctx->domain, sizeof(dns_name_t));
00132         }
00133         if (tctx->gssapi_keytab != NULL) {
00134                 isc_mem_free(mctx, tctx->gssapi_keytab);
00135         }
00136         if (tctx->gsscred != NULL)
00137                 dst_gssapi_releasecred(&tctx->gsscred);
00138         isc_entropy_detach(&tctx->ectx);
00139         isc_mem_put(mctx, tctx, sizeof(dns_tkeyctx_t));
00140         isc_mem_detach(&mctx);
00141         *tctxp = NULL;
00142 }
00143 
00144 static isc_result_t
00145 add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata,
00146                 isc_uint32_t ttl, dns_namelist_t *namelist)
00147 {
00148         isc_result_t result;
00149         isc_region_t r, newr;
00150         dns_rdata_t *newrdata = NULL;
00151         dns_name_t *newname = NULL;
00152         dns_rdatalist_t *newlist = NULL;
00153         dns_rdataset_t *newset = NULL;
00154         isc_buffer_t *tmprdatabuf = NULL;
00155 
00156         RETERR(dns_message_gettemprdata(msg, &newrdata));
00157 
00158         dns_rdata_toregion(rdata, &r);
00159         RETERR(isc_buffer_allocate(msg->mctx, &tmprdatabuf, r.length));
00160         isc_buffer_availableregion(tmprdatabuf, &newr);
00161         memmove(newr.base, r.base, r.length);
00162         dns_rdata_fromregion(newrdata, rdata->rdclass, rdata->type, &newr);
00163         dns_message_takebuffer(msg, &tmprdatabuf);
00164 
00165         RETERR(dns_message_gettempname(msg, &newname));
00166         dns_name_init(newname, NULL);
00167         RETERR(dns_name_dup(name, msg->mctx, newname));
00168 
00169         RETERR(dns_message_gettemprdatalist(msg, &newlist));
00170         newlist->rdclass = newrdata->rdclass;
00171         newlist->type = newrdata->type;
00172         newlist->ttl = ttl;
00173         ISC_LIST_APPEND(newlist->rdata, newrdata, link);
00174 
00175         RETERR(dns_message_gettemprdataset(msg, &newset));
00176         dns_rdataset_init(newset);
00177         RETERR(dns_rdatalist_tordataset(newlist, newset));
00178 
00179         ISC_LIST_INIT(newname->list);
00180         ISC_LIST_APPEND(newname->list, newset, link);
00181 
00182         ISC_LIST_APPEND(*namelist, newname, link);
00183 
00184         return (ISC_R_SUCCESS);
00185 
00186  failure:
00187         if (newrdata != NULL) {
00188                 if (ISC_LINK_LINKED(newrdata, link)) {
00189                         INSIST(newlist != NULL);
00190                         ISC_LIST_UNLINK(newlist->rdata, newrdata, link);
00191                 }
00192                 dns_message_puttemprdata(msg, &newrdata);
00193         }
00194         if (newname != NULL)
00195                 dns_message_puttempname(msg, &newname);
00196         if (newset != NULL) {
00197                 dns_rdataset_disassociate(newset);
00198                 dns_message_puttemprdataset(msg, &newset);
00199         }
00200         if (newlist != NULL)
00201                 dns_message_puttemprdatalist(msg, &newlist);
00202         return (result);
00203 }
00204 
00205 static void
00206 free_namelist(dns_message_t *msg, dns_namelist_t *namelist) {
00207         dns_name_t *name;
00208         dns_rdataset_t *set;
00209 
00210         while (!ISC_LIST_EMPTY(*namelist)) {
00211                 name = ISC_LIST_HEAD(*namelist);
00212                 ISC_LIST_UNLINK(*namelist, name, link);
00213                 while (!ISC_LIST_EMPTY(name->list)) {
00214                         set = ISC_LIST_HEAD(name->list);
00215                         ISC_LIST_UNLINK(name->list, set, link);
00216                         dns_message_puttemprdataset(msg, &set);
00217                 }
00218                 dns_message_puttempname(msg, &name);
00219         }
00220 }
00221 
00222 static isc_result_t
00223 compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness,
00224                isc_region_t *serverrandomness, isc_buffer_t *secret)
00225 {
00226         isc_md5_t md5ctx;
00227         isc_region_t r, r2;
00228         unsigned char digests[32];
00229         unsigned int i;
00230 
00231         isc_buffer_usedregion(shared, &r);
00232 
00233         /*
00234          * MD5 ( query data | DH value ).
00235          */
00236         isc_md5_init(&md5ctx);
00237         isc_md5_update(&md5ctx, queryrandomness->base,
00238                        queryrandomness->length);
00239         isc_md5_update(&md5ctx, r.base, r.length);
00240         isc_md5_final(&md5ctx, digests);
00241 
00242         /*
00243          * MD5 ( server data | DH value ).
00244          */
00245         isc_md5_init(&md5ctx);
00246         isc_md5_update(&md5ctx, serverrandomness->base,
00247                        serverrandomness->length);
00248         isc_md5_update(&md5ctx, r.base, r.length);
00249         isc_md5_final(&md5ctx, &digests[ISC_MD5_DIGESTLENGTH]);
00250 
00251         /*
00252          * XOR ( DH value, MD5-1 | MD5-2).
00253          */
00254         isc_buffer_availableregion(secret, &r);
00255         isc_buffer_usedregion(shared, &r2);
00256         if (r.length < sizeof(digests) || r.length < r2.length)
00257                 return (ISC_R_NOSPACE);
00258         if (r2.length > sizeof(digests)) {
00259                 memmove(r.base, r2.base, r2.length);
00260                 for (i = 0; i < sizeof(digests); i++)
00261                         r.base[i] ^= digests[i];
00262                 isc_buffer_add(secret, r2.length);
00263         } else {
00264                 memmove(r.base, digests, sizeof(digests));
00265                 for (i = 0; i < r2.length; i++)
00266                         r.base[i] ^= r2.base[i];
00267                 isc_buffer_add(secret, sizeof(digests));
00268         }
00269         return (ISC_R_SUCCESS);
00270 
00271 }
00272 
00273 static isc_result_t
00274 process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
00275                dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx,
00276                dns_rdata_tkey_t *tkeyout,
00277                dns_tsig_keyring_t *ring, dns_namelist_t *namelist)
00278 {
00279         isc_result_t result = ISC_R_SUCCESS;
00280         dns_name_t *keyname, ourname;
00281         dns_rdataset_t *keyset = NULL;
00282         dns_rdata_t keyrdata = DNS_RDATA_INIT, ourkeyrdata = DNS_RDATA_INIT;
00283         isc_boolean_t found_key = ISC_FALSE, found_incompatible = ISC_FALSE;
00284         dst_key_t *pubkey = NULL;
00285         isc_buffer_t ourkeybuf, *shared = NULL;
00286         isc_region_t r, r2, ourkeyr;
00287         unsigned char keydata[DST_KEY_MAXSIZE];
00288         unsigned int sharedsize;
00289         isc_buffer_t secret;
00290         unsigned char *randomdata = NULL, secretdata[256];
00291         dns_ttl_t ttl = 0;
00292 
00293         if (tctx->dhkey == NULL) {
00294                 tkey_log("process_dhtkey: tkey-dhkey not defined");
00295                 tkeyout->error = dns_tsigerror_badalg;
00296                 return (DNS_R_REFUSED);
00297         }
00298 
00299         if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) {
00300                 tkey_log("process_dhtkey: algorithms other than "
00301                          "hmac-md5 are not supported");
00302                 tkeyout->error = dns_tsigerror_badalg;
00303                 return (ISC_R_SUCCESS);
00304         }
00305 
00306         /*
00307          * Look for a DH KEY record that will work with ours.
00308          */
00309         for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL);
00310              result == ISC_R_SUCCESS && !found_key;
00311              result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) {
00312                 keyname = NULL;
00313                 dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname);
00314                 keyset = NULL;
00315                 result = dns_message_findtype(keyname, dns_rdatatype_key, 0,
00316                                               &keyset);
00317                 if (result != ISC_R_SUCCESS)
00318                         continue;
00319 
00320                 for (result = dns_rdataset_first(keyset);
00321                      result == ISC_R_SUCCESS && !found_key;
00322                      result = dns_rdataset_next(keyset)) {
00323                         dns_rdataset_current(keyset, &keyrdata);
00324                         pubkey = NULL;
00325                         result = dns_dnssec_keyfromrdata(keyname, &keyrdata,
00326                                                          msg->mctx, &pubkey);
00327                         if (result != ISC_R_SUCCESS) {
00328                                 dns_rdata_reset(&keyrdata);
00329                                 continue;
00330                         }
00331                         if (dst_key_alg(pubkey) == DNS_KEYALG_DH) {
00332                                 if (dst_key_paramcompare(pubkey, tctx->dhkey))
00333                                 {
00334                                         found_key = ISC_TRUE;
00335                                         ttl = keyset->ttl;
00336                                         break;
00337                                 } else
00338                                         found_incompatible = ISC_TRUE;
00339                         }
00340                         dst_key_free(&pubkey);
00341                         dns_rdata_reset(&keyrdata);
00342                 }
00343         }
00344 
00345         if (!found_key) {
00346                 if (found_incompatible) {
00347                         tkey_log("process_dhtkey: found an incompatible key");
00348                         tkeyout->error = dns_tsigerror_badkey;
00349                         return (ISC_R_SUCCESS);
00350                 } else {
00351                         tkey_log("process_dhtkey: failed to find a key");
00352                         return (DNS_R_FORMERR);
00353                 }
00354         }
00355 
00356         RETERR(add_rdata_to_list(msg, keyname, &keyrdata, ttl, namelist));
00357 
00358         isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata));
00359         RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf));
00360         isc_buffer_usedregion(&ourkeybuf, &ourkeyr);
00361         dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_any,
00362                              dns_rdatatype_key, &ourkeyr);
00363 
00364         dns_name_init(&ourname, NULL);
00365         dns_name_clone(dst_key_name(tctx->dhkey), &ourname);
00366 
00367         /*
00368          * XXXBEW The TTL should be obtained from the database, if it exists.
00369          */
00370         RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, 0, namelist));
00371 
00372         RETERR(dst_key_secretsize(tctx->dhkey, &sharedsize));
00373         RETERR(isc_buffer_allocate(msg->mctx, &shared, sharedsize));
00374 
00375         result = dst_key_computesecret(pubkey, tctx->dhkey, shared);
00376         if (result != ISC_R_SUCCESS) {
00377                 tkey_log("process_dhtkey: failed to compute shared secret: %s",
00378                          isc_result_totext(result));
00379                 goto failure;
00380         }
00381         dst_key_free(&pubkey);
00382 
00383         isc_buffer_init(&secret, secretdata, sizeof(secretdata));
00384 
00385         randomdata = isc_mem_get(tkeyout->mctx, TKEY_RANDOM_AMOUNT);
00386         if (randomdata == NULL)
00387                 goto failure;
00388 
00389         result = dst__entropy_getdata(randomdata, TKEY_RANDOM_AMOUNT,
00390                                       ISC_FALSE);
00391         if (result != ISC_R_SUCCESS) {
00392                 tkey_log("process_dhtkey: failed to obtain entropy: %s",
00393                          isc_result_totext(result));
00394                 goto failure;
00395         }
00396 
00397         r.base = randomdata;
00398         r.length = TKEY_RANDOM_AMOUNT;
00399         r2.base = tkeyin->key;
00400         r2.length = tkeyin->keylen;
00401         RETERR(compute_secret(shared, &r2, &r, &secret));
00402         isc_buffer_free(&shared);
00403 
00404         RETERR(dns_tsigkey_create(name, &tkeyin->algorithm,
00405                                   isc_buffer_base(&secret),
00406                                   isc_buffer_usedlength(&secret),
00407                                   ISC_TRUE, signer, tkeyin->inception,
00408                                   tkeyin->expire, ring->mctx, ring, NULL));
00409 
00410         /* This key is good for a long time */
00411         tkeyout->inception = tkeyin->inception;
00412         tkeyout->expire = tkeyin->expire;
00413 
00414         tkeyout->key = randomdata;
00415         tkeyout->keylen = TKEY_RANDOM_AMOUNT;
00416 
00417         return (ISC_R_SUCCESS);
00418 
00419  failure:
00420         if (!ISC_LIST_EMPTY(*namelist))
00421                 free_namelist(msg, namelist);
00422         if (shared != NULL)
00423                 isc_buffer_free(&shared);
00424         if (pubkey != NULL)
00425                 dst_key_free(&pubkey);
00426         if (randomdata != NULL)
00427                 isc_mem_put(tkeyout->mctx, randomdata, TKEY_RANDOM_AMOUNT);
00428         return (result);
00429 }
00430 
00431 static isc_result_t
00432 process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin,
00433                 dns_tkeyctx_t *tctx, dns_rdata_tkey_t *tkeyout,
00434                 dns_tsig_keyring_t *ring)
00435 {
00436         isc_result_t result = ISC_R_SUCCESS;
00437         dst_key_t *dstkey = NULL;
00438         dns_tsigkey_t *tsigkey = NULL;
00439         dns_fixedname_t principal;
00440         isc_stdtime_t now;
00441         isc_region_t intoken;
00442         isc_buffer_t *outtoken = NULL;
00443         gss_ctx_id_t gss_ctx = NULL;
00444 
00445         /*
00446          * You have to define either a gss credential (principal) to
00447          * accept with tkey-gssapi-credential, or you have to
00448          * configure a specific keytab (with tkey-gssapi-keytab) in
00449          * order to use gsstkey
00450          */
00451         if (tctx->gsscred == NULL && tctx->gssapi_keytab == NULL) {
00452                 tkey_log("process_gsstkey(): no tkey-gssapi-credential "
00453                          "or tkey-gssapi-keytab configured");
00454                 return (ISC_R_NOPERM);
00455         }
00456 
00457         if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) &&
00458             !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
00459                 tkeyout->error = dns_tsigerror_badalg;
00460                 tkey_log("process_gsstkey(): dns_tsigerror_badalg");    /* XXXSRA */
00461                 return (ISC_R_SUCCESS);
00462         }
00463 
00464         /*
00465          * XXXDCL need to check for key expiry per 4.1.1
00466          * XXXDCL need a way to check fully established, perhaps w/key_flags
00467          */
00468 
00469         intoken.base = tkeyin->key;
00470         intoken.length = tkeyin->keylen;
00471 
00472         result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
00473         if (result == ISC_R_SUCCESS)
00474                 gss_ctx = dst_key_getgssctx(tsigkey->key);
00475 
00476         dns_fixedname_init(&principal);
00477 
00478         /*
00479          * Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set
00480          */
00481         result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab,
00482                                       &intoken,
00483                                       &outtoken, &gss_ctx,
00484                                       dns_fixedname_name(&principal),
00485                                       tctx->mctx);
00486         if (result == DNS_R_INVALIDTKEY) {
00487                 if (tsigkey != NULL)
00488                         dns_tsigkey_detach(&tsigkey);
00489                 tkeyout->error = dns_tsigerror_badkey;
00490                 tkey_log("process_gsstkey(): dns_tsigerror_badkey");    /* XXXSRA */
00491                 return (ISC_R_SUCCESS);
00492         }
00493         if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
00494                 goto failure;
00495         /*
00496          * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times.
00497          */
00498 
00499         isc_stdtime_get(&now);
00500 
00501         if (tsigkey == NULL) {
00502 #ifdef GSSAPI
00503                 OM_uint32 gret, minor, lifetime;
00504 #endif
00505                 isc_uint32_t expire;
00506 
00507                 RETERR(dst_key_fromgssapi(name, gss_ctx, ring->mctx,
00508                                           &dstkey, &intoken));
00509                 /*
00510                  * Limit keys to 1 hour or the context's lifetime whichever
00511                  * is smaller.
00512                  */
00513                 expire = now + 3600;
00514 #ifdef GSSAPI
00515                 gret = gss_context_time(&minor, gss_ctx, &lifetime);
00516                 if (gret == GSS_S_COMPLETE && now + lifetime < expire)
00517                         expire = now + lifetime;
00518 #endif
00519                 RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
00520                                                  dstkey, ISC_TRUE,
00521                                                  dns_fixedname_name(&principal),
00522                                                  now, expire, ring->mctx, ring,
00523                                                  NULL));
00524                 dst_key_free(&dstkey);
00525                 tkeyout->inception = now;
00526                 tkeyout->expire = expire;
00527         } else {
00528                 tkeyout->inception = tsigkey->inception;
00529                 tkeyout->expire = tsigkey->expire;
00530                 dns_tsigkey_detach(&tsigkey);
00531         }
00532 
00533         if (outtoken) {
00534                 tkeyout->key = isc_mem_get(tkeyout->mctx,
00535                                            isc_buffer_usedlength(outtoken));
00536                 if (tkeyout->key == NULL) {
00537                         result = ISC_R_NOMEMORY;
00538                         goto failure;
00539                 }
00540                 tkeyout->keylen = isc_buffer_usedlength(outtoken);
00541                 memmove(tkeyout->key, isc_buffer_base(outtoken),
00542                        isc_buffer_usedlength(outtoken));
00543                 isc_buffer_free(&outtoken);
00544         } else {
00545                 tkeyout->key = isc_mem_get(tkeyout->mctx, tkeyin->keylen);
00546                 if (tkeyout->key == NULL) {
00547                         result = ISC_R_NOMEMORY;
00548                         goto failure;
00549                 }
00550                 tkeyout->keylen = tkeyin->keylen;
00551                 memmove(tkeyout->key, tkeyin->key, tkeyin->keylen);
00552         }
00553 
00554         tkeyout->error = dns_rcode_noerror;
00555 
00556         tkey_log("process_gsstkey(): dns_tsigerror_noerror");   /* XXXSRA */
00557 
00558         return (ISC_R_SUCCESS);
00559 
00560 failure:
00561         if (tsigkey != NULL)
00562                 dns_tsigkey_detach(&tsigkey);
00563 
00564         if (dstkey != NULL)
00565                 dst_key_free(&dstkey);
00566 
00567         if (outtoken != NULL)
00568                 isc_buffer_free(&outtoken);
00569 
00570         tkey_log("process_gsstkey(): %s",
00571                 isc_result_totext(result));     /* XXXSRA */
00572 
00573         return (result);
00574 }
00575 
00576 static isc_result_t
00577 process_deletetkey(dns_name_t *signer, dns_name_t *name,
00578                    dns_rdata_tkey_t *tkeyin, dns_rdata_tkey_t *tkeyout,
00579                    dns_tsig_keyring_t *ring)
00580 {
00581         isc_result_t result;
00582         dns_tsigkey_t *tsigkey = NULL;
00583         dns_name_t *identity;
00584 
00585         result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
00586         if (result != ISC_R_SUCCESS) {
00587                 tkeyout->error = dns_tsigerror_badname;
00588                 return (ISC_R_SUCCESS);
00589         }
00590 
00591         /*
00592          * Only allow a delete if the identity that created the key is the
00593          * same as the identity that signed the message.
00594          */
00595         identity = dns_tsigkey_identity(tsigkey);
00596         if (identity == NULL || !dns_name_equal(identity, signer)) {
00597                 dns_tsigkey_detach(&tsigkey);
00598                 return (DNS_R_REFUSED);
00599         }
00600 
00601         /*
00602          * Set the key to be deleted when no references are left.  If the key
00603          * was not generated with TKEY and is in the config file, it may be
00604          * reloaded later.
00605          */
00606         dns_tsigkey_setdeleted(tsigkey);
00607 
00608         /* Release the reference */
00609         dns_tsigkey_detach(&tsigkey);
00610 
00611         return (ISC_R_SUCCESS);
00612 }
00613 
00614 isc_result_t
00615 dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
00616                       dns_tsig_keyring_t *ring)
00617 {
00618         isc_result_t result = ISC_R_SUCCESS;
00619         dns_rdata_tkey_t tkeyin, tkeyout;
00620         isc_boolean_t freetkeyin = ISC_FALSE;
00621         dns_name_t *qname, *name, *keyname, *signer, tsigner;
00622         dns_fixedname_t fkeyname;
00623         dns_rdataset_t *tkeyset;
00624         dns_rdata_t rdata;
00625         dns_namelist_t namelist;
00626         char tkeyoutdata[512];
00627         isc_buffer_t tkeyoutbuf;
00628 
00629         REQUIRE(msg != NULL);
00630         REQUIRE(tctx != NULL);
00631         REQUIRE(ring != NULL);
00632 
00633         ISC_LIST_INIT(namelist);
00634 
00635         /*
00636          * Interpret the question section.
00637          */
00638         result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
00639         if (result != ISC_R_SUCCESS)
00640                 return (DNS_R_FORMERR);
00641 
00642         qname = NULL;
00643         dns_message_currentname(msg, DNS_SECTION_QUESTION, &qname);
00644 
00645         /*
00646          * Look for a TKEY record that matches the question.
00647          */
00648         tkeyset = NULL;
00649         name = NULL;
00650         result = dns_message_findname(msg, DNS_SECTION_ADDITIONAL, qname,
00651                                       dns_rdatatype_tkey, 0, &name, &tkeyset);
00652         if (result != ISC_R_SUCCESS) {
00653                 /*
00654                  * Try the answer section, since that's where Win2000
00655                  * puts it.
00656                  */
00657                 if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
00658                                          dns_rdatatype_tkey, 0, &name,
00659                                          &tkeyset) != ISC_R_SUCCESS) {
00660                         result = DNS_R_FORMERR;
00661                         tkey_log("dns_tkey_processquery: couldn't find a TKEY "
00662                                  "matching the question");
00663                         goto failure;
00664                 }
00665         }
00666         result = dns_rdataset_first(tkeyset);
00667         if (result != ISC_R_SUCCESS) {
00668                 result = DNS_R_FORMERR;
00669                 goto failure;
00670         }
00671         dns_rdata_init(&rdata);
00672         dns_rdataset_current(tkeyset, &rdata);
00673 
00674         RETERR(dns_rdata_tostruct(&rdata, &tkeyin, NULL));
00675         freetkeyin = ISC_TRUE;
00676 
00677         if (tkeyin.error != dns_rcode_noerror) {
00678                 result = DNS_R_FORMERR;
00679                 goto failure;
00680         }
00681 
00682         /*
00683          * Before we go any farther, verify that the message was signed.
00684          * GSSAPI TKEY doesn't require a signature, the rest do.
00685          */
00686         dns_name_init(&tsigner, NULL);
00687         result = dns_message_signer(msg, &tsigner);
00688         if (result != ISC_R_SUCCESS) {
00689                 if (tkeyin.mode == DNS_TKEYMODE_GSSAPI &&
00690                     result == ISC_R_NOTFOUND)
00691                        signer = NULL;
00692                 else {
00693                         tkey_log("dns_tkey_processquery: query was not "
00694                                  "properly signed - rejecting");
00695                         result = DNS_R_FORMERR;
00696                         goto failure;
00697                 }
00698         } else
00699                 signer = &tsigner;
00700 
00701         tkeyout.common.rdclass = tkeyin.common.rdclass;
00702         tkeyout.common.rdtype = tkeyin.common.rdtype;
00703         ISC_LINK_INIT(&tkeyout.common, link);
00704         tkeyout.mctx = msg->mctx;
00705 
00706         dns_name_init(&tkeyout.algorithm, NULL);
00707         dns_name_clone(&tkeyin.algorithm, &tkeyout.algorithm);
00708 
00709         tkeyout.inception = tkeyout.expire = 0;
00710         tkeyout.mode = tkeyin.mode;
00711         tkeyout.error = 0;
00712         tkeyout.keylen = tkeyout.otherlen = 0;
00713         tkeyout.key = tkeyout.other = NULL;
00714 
00715         /*
00716          * A delete operation must have a fully specified key name.  If this
00717          * is not a delete, we do the following:
00718          * if (qname != ".")
00719          *      keyname = qname + defaultdomain
00720          * else
00721          *      keyname = <random hex> + defaultdomain
00722          */
00723         if (tkeyin.mode != DNS_TKEYMODE_DELETE) {
00724                 dns_tsigkey_t *tsigkey = NULL;
00725 
00726                 if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) {
00727                         tkey_log("dns_tkey_processquery: tkey-domain not set");
00728                         result = DNS_R_REFUSED;
00729                         goto failure;
00730                 }
00731 
00732                 dns_fixedname_init(&fkeyname);
00733                 keyname = dns_fixedname_name(&fkeyname);
00734 
00735                 if (!dns_name_equal(qname, dns_rootname)) {
00736                         unsigned int n = dns_name_countlabels(qname);
00737                         RUNTIME_CHECK(dns_name_copy(qname, keyname, NULL)
00738                                       == ISC_R_SUCCESS);
00739                         dns_name_getlabelsequence(keyname, 0, n - 1, keyname);
00740                 } else {
00741                         static char hexdigits[16] = {
00742                                 '0', '1', '2', '3', '4', '5', '6', '7',
00743                                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
00744                         unsigned char randomdata[16];
00745                         char randomtext[32];
00746                         isc_buffer_t b;
00747                         unsigned int i, j;
00748 
00749                         result = isc_entropy_getdata(tctx->ectx,
00750                                                      randomdata,
00751                                                      sizeof(randomdata),
00752                                                      NULL, 0);
00753                         if (result != ISC_R_SUCCESS)
00754                                 goto failure;
00755 
00756                         for (i = 0, j = 0; i < sizeof(randomdata); i++) {
00757                                 unsigned char val = randomdata[i];
00758                                 randomtext[j++] = hexdigits[val >> 4];
00759                                 randomtext[j++] = hexdigits[val & 0xF];
00760                         }
00761                         isc_buffer_init(&b, randomtext, sizeof(randomtext));
00762                         isc_buffer_add(&b, sizeof(randomtext));
00763                         result = dns_name_fromtext(keyname, &b, NULL, 0, NULL);
00764                         if (result != ISC_R_SUCCESS)
00765                                 goto failure;
00766                 }
00767 
00768                 if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) {
00769                         /* Yup.  This is a hack */
00770                         result = dns_name_concatenate(keyname, dns_rootname,
00771                                                       keyname, NULL);
00772                         if (result != ISC_R_SUCCESS)
00773                                 goto failure;
00774                 } else {
00775                         result = dns_name_concatenate(keyname, tctx->domain,
00776                                                       keyname, NULL);
00777                         if (result != ISC_R_SUCCESS)
00778                                 goto failure;
00779                 }
00780 
00781                 result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring);
00782 
00783                 if (result == ISC_R_SUCCESS) {
00784                         tkeyout.error = dns_tsigerror_badname;
00785                         dns_tsigkey_detach(&tsigkey);
00786                         goto failure_with_tkey;
00787                 } else if (result != ISC_R_NOTFOUND)
00788                         goto failure;
00789         } else
00790                 keyname = qname;
00791 
00792         switch (tkeyin.mode) {
00793                 case DNS_TKEYMODE_DIFFIEHELLMAN:
00794                         tkeyout.error = dns_rcode_noerror;
00795                         RETERR(process_dhtkey(msg, signer, keyname, &tkeyin,
00796                                               tctx, &tkeyout, ring,
00797                                               &namelist));
00798                         break;
00799                 case DNS_TKEYMODE_GSSAPI:
00800                         tkeyout.error = dns_rcode_noerror;
00801                         RETERR(process_gsstkey(keyname, &tkeyin, tctx,
00802                                                &tkeyout, ring));
00803                         break;
00804                 case DNS_TKEYMODE_DELETE:
00805                         tkeyout.error = dns_rcode_noerror;
00806                         RETERR(process_deletetkey(signer, keyname, &tkeyin,
00807                                                   &tkeyout, ring));
00808                         break;
00809                 case DNS_TKEYMODE_SERVERASSIGNED:
00810                 case DNS_TKEYMODE_RESOLVERASSIGNED:
00811                         result = DNS_R_NOTIMP;
00812                         goto failure;
00813                 default:
00814                         tkeyout.error = dns_tsigerror_badmode;
00815         }
00816 
00817  failure_with_tkey:
00818         dns_rdata_init(&rdata);
00819         isc_buffer_init(&tkeyoutbuf, tkeyoutdata, sizeof(tkeyoutdata));
00820         result = dns_rdata_fromstruct(&rdata, tkeyout.common.rdclass,
00821                                       tkeyout.common.rdtype, &tkeyout,
00822                                       &tkeyoutbuf);
00823 
00824         if (freetkeyin) {
00825                 dns_rdata_freestruct(&tkeyin);
00826                 freetkeyin = ISC_FALSE;
00827         }
00828 
00829         if (tkeyout.key != NULL)
00830                 isc_mem_put(tkeyout.mctx, tkeyout.key, tkeyout.keylen);
00831         if (tkeyout.other != NULL)
00832                 isc_mem_put(tkeyout.mctx, tkeyout.other, tkeyout.otherlen);
00833         if (result != ISC_R_SUCCESS)
00834                 goto failure;
00835 
00836         RETERR(add_rdata_to_list(msg, keyname, &rdata, 0, &namelist));
00837 
00838         RETERR(dns_message_reply(msg, ISC_TRUE));
00839 
00840         name = ISC_LIST_HEAD(namelist);
00841         while (name != NULL) {
00842                 dns_name_t *next = ISC_LIST_NEXT(name, link);
00843                 ISC_LIST_UNLINK(namelist, name, link);
00844                 dns_message_addname(msg, name, DNS_SECTION_ANSWER);
00845                 name = next;
00846         }
00847 
00848         return (ISC_R_SUCCESS);
00849 
00850  failure:
00851         if (freetkeyin)
00852                 dns_rdata_freestruct(&tkeyin);
00853         if (!ISC_LIST_EMPTY(namelist))
00854                 free_namelist(msg, &namelist);
00855         return (result);
00856 }
00857 
00858 static isc_result_t
00859 buildquery(dns_message_t *msg, dns_name_t *name,
00860            dns_rdata_tkey_t *tkey, isc_boolean_t win2k)
00861 {
00862         dns_name_t *qname = NULL, *aname = NULL;
00863         dns_rdataset_t *question = NULL, *tkeyset = NULL;
00864         dns_rdatalist_t *tkeylist = NULL;
00865         dns_rdata_t *rdata = NULL;
00866         isc_buffer_t *dynbuf = NULL, *anamebuf = NULL, *qnamebuf = NULL;
00867         isc_result_t result;
00868 
00869         REQUIRE(msg != NULL);
00870         REQUIRE(name != NULL);
00871         REQUIRE(tkey != NULL);
00872 
00873         RETERR(dns_message_gettempname(msg, &qname));
00874         RETERR(dns_message_gettempname(msg, &aname));
00875 
00876         RETERR(dns_message_gettemprdataset(msg, &question));
00877         dns_rdataset_init(question);
00878         dns_rdataset_makequestion(question, dns_rdataclass_any,
00879                                   dns_rdatatype_tkey);
00880 
00881         RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 4096));
00882         RETERR(isc_buffer_allocate(msg->mctx, &anamebuf, DNS_NAME_MAXWIRE));
00883         RETERR(isc_buffer_allocate(msg->mctx, &qnamebuf, DNS_NAME_MAXWIRE));
00884         RETERR(dns_message_gettemprdata(msg, &rdata));
00885 
00886         RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
00887                                     dns_rdatatype_tkey, tkey, dynbuf));
00888         dns_message_takebuffer(msg, &dynbuf);
00889 
00890         RETERR(dns_message_gettemprdatalist(msg, &tkeylist));
00891         tkeylist->rdclass = dns_rdataclass_any;
00892         tkeylist->type = dns_rdatatype_tkey;
00893         ISC_LIST_APPEND(tkeylist->rdata, rdata, link);
00894 
00895         RETERR(dns_message_gettemprdataset(msg, &tkeyset));
00896         dns_rdataset_init(tkeyset);
00897         RETERR(dns_rdatalist_tordataset(tkeylist, tkeyset));
00898 
00899         dns_name_init(qname, NULL);
00900         dns_name_copy(name, qname, qnamebuf);
00901 
00902         dns_name_init(aname, NULL);
00903         dns_name_copy(name, aname, anamebuf);
00904 
00905         ISC_LIST_APPEND(qname->list, question, link);
00906         ISC_LIST_APPEND(aname->list, tkeyset, link);
00907 
00908         dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
00909         dns_message_takebuffer(msg, &qnamebuf);
00910 
00911         /*
00912          * Windows 2000 needs this in the answer section, not the additional
00913          * section where the RFC specifies.
00914          */
00915         if (win2k)
00916                 dns_message_addname(msg, aname, DNS_SECTION_ANSWER);
00917         else
00918                 dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL);
00919         dns_message_takebuffer(msg, &anamebuf);
00920 
00921         return (ISC_R_SUCCESS);
00922 
00923  failure:
00924         if (qname != NULL)
00925                 dns_message_puttempname(msg, &qname);
00926         if (aname != NULL)
00927                 dns_message_puttempname(msg, &aname);
00928         if (question != NULL) {
00929                 dns_rdataset_disassociate(question);
00930                 dns_message_puttemprdataset(msg, &question);
00931         }
00932         if (dynbuf != NULL)
00933                 isc_buffer_free(&dynbuf);
00934         if (qnamebuf != NULL)
00935                 isc_buffer_free(&qnamebuf);
00936         if (anamebuf != NULL)
00937                 isc_buffer_free(&anamebuf);
00938         printf("buildquery error\n");
00939         return (result);
00940 }
00941 
00942 isc_result_t
00943 dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
00944                       dns_name_t *algorithm, isc_buffer_t *nonce,
00945                       isc_uint32_t lifetime)
00946 {
00947         dns_rdata_tkey_t tkey;
00948         dns_rdata_t *rdata = NULL;
00949         isc_buffer_t *dynbuf = NULL;
00950         isc_region_t r;
00951         dns_name_t keyname;
00952         dns_namelist_t namelist;
00953         isc_result_t result;
00954         isc_stdtime_t now;
00955 
00956         REQUIRE(msg != NULL);
00957         REQUIRE(key != NULL);
00958         REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH);
00959         REQUIRE(dst_key_isprivate(key));
00960         REQUIRE(name != NULL);
00961         REQUIRE(algorithm != NULL);
00962 
00963         tkey.common.rdclass = dns_rdataclass_any;
00964         tkey.common.rdtype = dns_rdatatype_tkey;
00965         ISC_LINK_INIT(&tkey.common, link);
00966         tkey.mctx = msg->mctx;
00967         dns_name_init(&tkey.algorithm, NULL);
00968         dns_name_clone(algorithm, &tkey.algorithm);
00969         isc_stdtime_get(&now);
00970         tkey.inception = now;
00971         tkey.expire = now + lifetime;
00972         tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN;
00973         if (nonce != NULL)
00974                 isc_buffer_usedregion(nonce, &r);
00975         else {
00976                 r.base = isc_mem_get(msg->mctx, 0);
00977                 r.length = 0;
00978         }
00979         tkey.error = 0;
00980         tkey.key = r.base;
00981         tkey.keylen =  r.length;
00982         tkey.other = NULL;
00983         tkey.otherlen = 0;
00984 
00985         RETERR(buildquery(msg, name, &tkey, ISC_FALSE));
00986 
00987         if (nonce == NULL)
00988                 isc_mem_put(msg->mctx, r.base, 0);
00989 
00990         RETERR(dns_message_gettemprdata(msg, &rdata));
00991         RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
00992         RETERR(dst_key_todns(key, dynbuf));
00993         isc_buffer_usedregion(dynbuf, &r);
00994         dns_rdata_fromregion(rdata, dns_rdataclass_any,
00995                              dns_rdatatype_key, &r);
00996         dns_message_takebuffer(msg, &dynbuf);
00997 
00998         dns_name_init(&keyname, NULL);
00999         dns_name_clone(dst_key_name(key), &keyname);
01000 
01001         ISC_LIST_INIT(namelist);
01002         RETERR(add_rdata_to_list(msg, &keyname, rdata, 0, &namelist));
01003         name = ISC_LIST_HEAD(namelist);
01004         while (name != NULL) {
01005                 dns_name_t *next = ISC_LIST_NEXT(name, link);
01006                 ISC_LIST_UNLINK(namelist, name, link);
01007                 dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
01008                 name = next;
01009         }
01010 
01011         return (ISC_R_SUCCESS);
01012 
01013  failure:
01014 
01015         if (dynbuf != NULL)
01016                 isc_buffer_free(&dynbuf);
01017         return (result);
01018 }
01019 
01020 isc_result_t
01021 dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
01022                        isc_buffer_t *intoken, isc_uint32_t lifetime,
01023                        gss_ctx_id_t *context, isc_boolean_t win2k,
01024                        isc_mem_t *mctx, char **err_message)
01025 {
01026         dns_rdata_tkey_t tkey;
01027         isc_result_t result;
01028         isc_stdtime_t now;
01029         isc_buffer_t token;
01030         unsigned char array[4096];
01031 
01032         UNUSED(intoken);
01033 
01034         REQUIRE(msg != NULL);
01035         REQUIRE(name != NULL);
01036         REQUIRE(gname != NULL);
01037         REQUIRE(context != NULL);
01038         REQUIRE(mctx != NULL);
01039 
01040         isc_buffer_init(&token, array, sizeof(array));
01041         result = dst_gssapi_initctx(gname, NULL, &token, context,
01042                                     mctx, err_message);
01043         if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
01044                 return (result);
01045 
01046         tkey.common.rdclass = dns_rdataclass_any;
01047         tkey.common.rdtype = dns_rdatatype_tkey;
01048         ISC_LINK_INIT(&tkey.common, link);
01049         tkey.mctx = NULL;
01050         dns_name_init(&tkey.algorithm, NULL);
01051 
01052         if (win2k)
01053                 dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm);
01054         else
01055                 dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm);
01056 
01057         isc_stdtime_get(&now);
01058         tkey.inception = now;
01059         tkey.expire = now + lifetime;
01060         tkey.mode = DNS_TKEYMODE_GSSAPI;
01061         tkey.error = 0;
01062         tkey.key = isc_buffer_base(&token);
01063         tkey.keylen = isc_buffer_usedlength(&token);
01064         tkey.other = NULL;
01065         tkey.otherlen = 0;
01066 
01067         RETERR(buildquery(msg, name, &tkey, win2k));
01068 
01069         return (ISC_R_SUCCESS);
01070 
01071  failure:
01072         return (result);
01073 }
01074 
01075 isc_result_t
01076 dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) {
01077         dns_rdata_tkey_t tkey;
01078 
01079         REQUIRE(msg != NULL);
01080         REQUIRE(key != NULL);
01081 
01082         tkey.common.rdclass = dns_rdataclass_any;
01083         tkey.common.rdtype = dns_rdatatype_tkey;
01084         ISC_LINK_INIT(&tkey.common, link);
01085         tkey.mctx = msg->mctx;
01086         dns_name_init(&tkey.algorithm, NULL);
01087         dns_name_clone(key->algorithm, &tkey.algorithm);
01088         tkey.inception = tkey.expire = 0;
01089         tkey.mode = DNS_TKEYMODE_DELETE;
01090         tkey.error = 0;
01091         tkey.keylen = tkey.otherlen = 0;
01092         tkey.key = tkey.other = NULL;
01093 
01094         return (buildquery(msg, &key->name, &tkey, ISC_FALSE));
01095 }
01096 
01097 static isc_result_t
01098 find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata,
01099           int section)
01100 {
01101         dns_rdataset_t *tkeyset;
01102         isc_result_t result;
01103 
01104         result = dns_message_firstname(msg, section);
01105         while (result == ISC_R_SUCCESS) {
01106                 *name = NULL;
01107                 dns_message_currentname(msg, section, name);
01108                 tkeyset = NULL;
01109                 result = dns_message_findtype(*name, dns_rdatatype_tkey, 0,
01110                                               &tkeyset);
01111                 if (result == ISC_R_SUCCESS) {
01112                         result = dns_rdataset_first(tkeyset);
01113                         if (result != ISC_R_SUCCESS)
01114                                 return (result);
01115                         dns_rdataset_current(tkeyset, rdata);
01116                         return (ISC_R_SUCCESS);
01117                 }
01118                 result = dns_message_nextname(msg, section);
01119         }
01120         if (result == ISC_R_NOMORE)
01121                 return (ISC_R_NOTFOUND);
01122         return (result);
01123 }
01124 
01125 isc_result_t
01126 dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
01127                            dst_key_t *key, isc_buffer_t *nonce,
01128                            dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring)
01129 {
01130         dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT;
01131         dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname;
01132         dns_rdataset_t *theirkeyset = NULL, *ourkeyset = NULL;
01133         dns_rdata_t theirkeyrdata = DNS_RDATA_INIT;
01134         dst_key_t *theirkey = NULL;
01135         dns_rdata_tkey_t qtkey, rtkey;
01136         unsigned char secretdata[256];
01137         unsigned int sharedsize;
01138         isc_buffer_t *shared = NULL, secret;
01139         isc_region_t r, r2;
01140         isc_result_t result;
01141         isc_boolean_t freertkey = ISC_FALSE;
01142 
01143         REQUIRE(qmsg != NULL);
01144         REQUIRE(rmsg != NULL);
01145         REQUIRE(key != NULL);
01146         REQUIRE(dst_key_alg(key) == DNS_KEYALG_DH);
01147         REQUIRE(dst_key_isprivate(key));
01148         if (outkey != NULL)
01149                 REQUIRE(*outkey == NULL);
01150 
01151         if (rmsg->rcode != dns_rcode_noerror)
01152                 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
01153         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
01154         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
01155         freertkey = ISC_TRUE;
01156 
01157         RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata,
01158                          DNS_SECTION_ADDITIONAL));
01159         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
01160 
01161         if (rtkey.error != dns_rcode_noerror ||
01162             rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN ||
01163             rtkey.mode != qtkey.mode ||
01164             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
01165             rmsg->rcode != dns_rcode_noerror) {
01166                 tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
01167                          "or error set(1)");
01168                 result = DNS_R_INVALIDTKEY;
01169                 dns_rdata_freestruct(&qtkey);
01170                 goto failure;
01171         }
01172 
01173         dns_rdata_freestruct(&qtkey);
01174 
01175         dns_name_init(&keyname, NULL);
01176         dns_name_clone(dst_key_name(key), &keyname);
01177 
01178         ourkeyname = NULL;
01179         ourkeyset = NULL;
01180         RETERR(dns_message_findname(rmsg, DNS_SECTION_ANSWER, &keyname,
01181                                     dns_rdatatype_key, 0, &ourkeyname,
01182                                     &ourkeyset));
01183 
01184         result = dns_message_firstname(rmsg, DNS_SECTION_ANSWER);
01185         while (result == ISC_R_SUCCESS) {
01186                 theirkeyname = NULL;
01187                 dns_message_currentname(rmsg, DNS_SECTION_ANSWER,
01188                                         &theirkeyname);
01189                 if (dns_name_equal(theirkeyname, ourkeyname))
01190                         goto next;
01191                 theirkeyset = NULL;
01192                 result = dns_message_findtype(theirkeyname, dns_rdatatype_key,
01193                                               0, &theirkeyset);
01194                 if (result == ISC_R_SUCCESS) {
01195                         RETERR(dns_rdataset_first(theirkeyset));
01196                         break;
01197                 }
01198  next:
01199                 result = dns_message_nextname(rmsg, DNS_SECTION_ANSWER);
01200         }
01201 
01202         if (theirkeyset == NULL) {
01203                 tkey_log("dns_tkey_processdhresponse: failed to find server "
01204                          "key");
01205                 result = ISC_R_NOTFOUND;
01206                 goto failure;
01207         }
01208 
01209         dns_rdataset_current(theirkeyset, &theirkeyrdata);
01210         RETERR(dns_dnssec_keyfromrdata(theirkeyname, &theirkeyrdata,
01211                                        rmsg->mctx, &theirkey));
01212 
01213         RETERR(dst_key_secretsize(key, &sharedsize));
01214         RETERR(isc_buffer_allocate(rmsg->mctx, &shared, sharedsize));
01215 
01216         RETERR(dst_key_computesecret(theirkey, key, shared));
01217 
01218         isc_buffer_init(&secret, secretdata, sizeof(secretdata));
01219 
01220         r.base = rtkey.key;
01221         r.length = rtkey.keylen;
01222         if (nonce != NULL)
01223                 isc_buffer_usedregion(nonce, &r2);
01224         else {
01225                 r2.base = isc_mem_get(rmsg->mctx, 0);
01226                 r2.length = 0;
01227         }
01228         RETERR(compute_secret(shared, &r2, &r, &secret));
01229         if (nonce == NULL)
01230                 isc_mem_put(rmsg->mctx, r2.base, 0);
01231 
01232         isc_buffer_usedregion(&secret, &r);
01233         result = dns_tsigkey_create(tkeyname, &rtkey.algorithm,
01234                                     r.base, r.length, ISC_TRUE,
01235                                     NULL, rtkey.inception, rtkey.expire,
01236                                     rmsg->mctx, ring, outkey);
01237         isc_buffer_free(&shared);
01238         dns_rdata_freestruct(&rtkey);
01239         dst_key_free(&theirkey);
01240         return (result);
01241 
01242  failure:
01243         if (shared != NULL)
01244                 isc_buffer_free(&shared);
01245 
01246         if (theirkey != NULL)
01247                 dst_key_free(&theirkey);
01248 
01249         if (freertkey)
01250                 dns_rdata_freestruct(&rtkey);
01251 
01252         return (result);
01253 }
01254 
01255 isc_result_t
01256 dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
01257                             dns_name_t *gname, gss_ctx_id_t *context,
01258                             isc_buffer_t *outtoken, dns_tsigkey_t **outkey,
01259                             dns_tsig_keyring_t *ring, char **err_message)
01260 {
01261         dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
01262         dns_name_t *tkeyname;
01263         dns_rdata_tkey_t rtkey, qtkey;
01264         dst_key_t *dstkey = NULL;
01265         isc_buffer_t intoken;
01266         isc_result_t result;
01267         unsigned char array[1024];
01268 
01269         REQUIRE(outtoken != NULL);
01270         REQUIRE(qmsg != NULL);
01271         REQUIRE(rmsg != NULL);
01272         REQUIRE(gname != NULL);
01273         REQUIRE(ring != NULL);
01274         if (outkey != NULL)
01275                 REQUIRE(*outkey == NULL);
01276 
01277         if (rmsg->rcode != dns_rcode_noerror)
01278                 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
01279         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
01280         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
01281 
01282         /*
01283          * Win2k puts the item in the ANSWER section, while the RFC
01284          * specifies it should be in the ADDITIONAL section.  Check first
01285          * where it should be, and then where it may be.
01286          */
01287         result = find_tkey(qmsg, &tkeyname, &qtkeyrdata,
01288                            DNS_SECTION_ADDITIONAL);
01289         if (result == ISC_R_NOTFOUND)
01290                 result = find_tkey(qmsg, &tkeyname, &qtkeyrdata,
01291                                    DNS_SECTION_ANSWER);
01292         if (result != ISC_R_SUCCESS)
01293                 goto failure;
01294 
01295         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
01296 
01297         if (rtkey.error != dns_rcode_noerror ||
01298             rtkey.mode != DNS_TKEYMODE_GSSAPI ||
01299             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) {
01300                 tkey_log("dns_tkey_processgssresponse: tkey mode invalid "
01301                          "or error set(2) %d", rtkey.error);
01302                 _dns_tkey_dumpmessage(qmsg);
01303                 _dns_tkey_dumpmessage(rmsg);
01304                 result = DNS_R_INVALIDTKEY;
01305                 goto failure;
01306         }
01307 
01308         isc_buffer_init(outtoken, array, sizeof(array));
01309         isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
01310         RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context,
01311                                   ring->mctx, err_message));
01312 
01313         RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
01314                                   &dstkey, NULL));
01315 
01316         RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME,
01317                                          dstkey, ISC_FALSE, NULL,
01318                                          rtkey.inception, rtkey.expire,
01319                                          ring->mctx, ring, outkey));
01320         dst_key_free(&dstkey);
01321         dns_rdata_freestruct(&rtkey);
01322         return (result);
01323 
01324  failure:
01325         /*
01326          * XXXSRA This probably leaks memory from rtkey and qtkey.
01327          */
01328         if (dstkey != NULL)
01329                 dst_key_free(&dstkey);
01330         return (result);
01331 }
01332 
01333 isc_result_t
01334 dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
01335                                dns_tsig_keyring_t *ring)
01336 {
01337         dns_rdata_t qtkeyrdata = DNS_RDATA_INIT, rtkeyrdata = DNS_RDATA_INIT;
01338         dns_name_t *tkeyname, *tempname;
01339         dns_rdata_tkey_t qtkey, rtkey;
01340         dns_tsigkey_t *tsigkey = NULL;
01341         isc_result_t result;
01342 
01343         REQUIRE(qmsg != NULL);
01344         REQUIRE(rmsg != NULL);
01345 
01346         if (rmsg->rcode != dns_rcode_noerror)
01347                 return(ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
01348 
01349         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
01350         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
01351 
01352         RETERR(find_tkey(qmsg, &tempname, &qtkeyrdata,
01353                          DNS_SECTION_ADDITIONAL));
01354         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
01355 
01356         if (rtkey.error != dns_rcode_noerror ||
01357             rtkey.mode != DNS_TKEYMODE_DELETE ||
01358             rtkey.mode != qtkey.mode ||
01359             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
01360             rmsg->rcode != dns_rcode_noerror) {
01361                 tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid "
01362                          "or error set(3)");
01363                 result = DNS_R_INVALIDTKEY;
01364                 dns_rdata_freestruct(&qtkey);
01365                 dns_rdata_freestruct(&rtkey);
01366                 goto failure;
01367         }
01368 
01369         dns_rdata_freestruct(&qtkey);
01370 
01371         RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm, ring));
01372 
01373         dns_rdata_freestruct(&rtkey);
01374 
01375         /*
01376          * Mark the key as deleted.
01377          */
01378         dns_tsigkey_setdeleted(tsigkey);
01379         /*
01380          * Release the reference.
01381          */
01382         dns_tsigkey_detach(&tsigkey);
01383 
01384  failure:
01385         return (result);
01386 }
01387 
01388 isc_result_t
01389 dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
01390                       dns_name_t *server, gss_ctx_id_t *context,
01391                       dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
01392                       isc_boolean_t win2k, char **err_message)
01393 {
01394         dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
01395         dns_name_t *tkeyname;
01396         dns_rdata_tkey_t rtkey, qtkey;
01397         isc_buffer_t intoken, outtoken;
01398         dst_key_t *dstkey = NULL;
01399         isc_result_t result;
01400         unsigned char array[1024];
01401         isc_boolean_t freertkey = ISC_FALSE;
01402 
01403         REQUIRE(qmsg != NULL);
01404         REQUIRE(rmsg != NULL);
01405         REQUIRE(server != NULL);
01406         if (outkey != NULL)
01407                 REQUIRE(*outkey == NULL);
01408 
01409         if (rmsg->rcode != dns_rcode_noerror)
01410                 return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
01411 
01412         RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
01413         RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
01414         freertkey = ISC_TRUE;
01415 
01416         if (win2k == ISC_TRUE)
01417                 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
01418                                  DNS_SECTION_ANSWER));
01419         else
01420                 RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
01421                                  DNS_SECTION_ADDITIONAL));
01422 
01423         RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
01424 
01425         if (rtkey.error != dns_rcode_noerror ||
01426             rtkey.mode != DNS_TKEYMODE_GSSAPI ||
01427             !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm))
01428         {
01429                 tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
01430                          "or error set(4)");
01431                 result = DNS_R_INVALIDTKEY;
01432                 goto failure;
01433         }
01434 
01435         isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
01436         isc_buffer_init(&outtoken, array, sizeof(array));
01437 
01438         result = dst_gssapi_initctx(server, &intoken, &outtoken, context,
01439                                     ring->mctx, err_message);
01440         if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
01441                 return (result);
01442 
01443         RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
01444                                   &dstkey, NULL));
01445 
01446         /*
01447          * XXXSRA This seems confused.  If we got CONTINUE from initctx,
01448          * the GSS negotiation hasn't completed yet, so we can't sign
01449          * anything yet.
01450          */
01451 
01452         RETERR(dns_tsigkey_createfromkey(tkeyname,
01453                                          (win2k
01454                                           ? DNS_TSIG_GSSAPIMS_NAME
01455                                           : DNS_TSIG_GSSAPI_NAME),
01456                                          dstkey, ISC_TRUE, NULL,
01457                                          rtkey.inception, rtkey.expire,
01458                                          ring->mctx, ring, outkey));
01459         dst_key_free(&dstkey);
01460         dns_rdata_freestruct(&rtkey);
01461         return (result);
01462 
01463  failure:
01464         /*
01465          * XXXSRA This probably leaks memory from qtkey.
01466          */
01467         if (freertkey)
01468                 dns_rdata_freestruct(&rtkey);
01469         if (dstkey != NULL)
01470                 dst_key_free(&dstkey);
01471         return (result);
01472 }

Generated on Tue Apr 28 17:41:02 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha