"Fossies" - the Fresh Open Source Software Archive

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


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

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <inttypes.h>
   15 #include <stdbool.h>
   16 #include <stdlib.h>
   17 
   18 #include <isc/buffer.h>
   19 #include <isc/mem.h>
   20 #include <isc/print.h>
   21 #include <isc/refcount.h>
   22 #include <isc/serial.h>
   23 #include <isc/string.h> /* Required for HP/UX (and others?) */
   24 #include <isc/time.h>
   25 #include <isc/util.h>
   26 
   27 #include <pk11/site.h>
   28 
   29 #include <dns/fixedname.h>
   30 #include <dns/keyvalues.h>
   31 #include <dns/log.h>
   32 #include <dns/message.h>
   33 #include <dns/rbt.h>
   34 #include <dns/rdata.h>
   35 #include <dns/rdatalist.h>
   36 #include <dns/rdataset.h>
   37 #include <dns/rdatastruct.h>
   38 #include <dns/result.h>
   39 #include <dns/tsig.h>
   40 
   41 #include <dst/result.h>
   42 
   43 #include "tsig_p.h"
   44 
   45 #define TSIG_MAGIC    ISC_MAGIC('T', 'S', 'I', 'G')
   46 #define VALID_TSIG_KEY(x) ISC_MAGIC_VALID(x, TSIG_MAGIC)
   47 
   48 #ifndef DNS_TSIG_MAXGENERATEDKEYS
   49 #define DNS_TSIG_MAXGENERATEDKEYS 4096
   50 #endif /* ifndef DNS_TSIG_MAXGENERATEDKEYS */
   51 
   52 #define is_response(msg) ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
   53 
   54 #define BADTIMELEN 6
   55 
   56 static unsigned char hmacmd5_ndata[] = "\010hmac-md5\007sig-alg\003reg\003int";
   57 static unsigned char hmacmd5_offsets[] = { 0, 9, 17, 21, 25 };
   58 
   59 static dns_name_t const hmacmd5 = DNS_NAME_INITABSOLUTE(hmacmd5_ndata,
   60                             hmacmd5_offsets);
   61 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
   62 
   63 static unsigned char gsstsig_ndata[] = "\010gss-tsig";
   64 static unsigned char gsstsig_offsets[] = { 0, 9 };
   65 static dns_name_t const gsstsig = DNS_NAME_INITABSOLUTE(gsstsig_ndata,
   66                             gsstsig_offsets);
   67 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_gssapi_name = &gsstsig;
   68 
   69 /*
   70  * Since Microsoft doesn't follow its own standard, we will use this
   71  * alternate name as a second guess.
   72  */
   73 static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com";
   74 static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 };
   75 static dns_name_t const gsstsigms = DNS_NAME_INITABSOLUTE(gsstsigms_ndata,
   76                               gsstsigms_offsets);
   77 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_gssapims_name = &gsstsigms;
   78 
   79 static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
   80 static unsigned char hmacsha1_offsets[] = { 0, 10 };
   81 static dns_name_t const hmacsha1 = DNS_NAME_INITABSOLUTE(hmacsha1_ndata,
   82                              hmacsha1_offsets);
   83 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1;
   84 
   85 static unsigned char hmacsha224_ndata[] = "\013hmac-sha224";
   86 static unsigned char hmacsha224_offsets[] = { 0, 12 };
   87 static dns_name_t const hmacsha224 = DNS_NAME_INITABSOLUTE(hmacsha224_ndata,
   88                                hmacsha224_offsets);
   89 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224;
   90 
   91 static unsigned char hmacsha256_ndata[] = "\013hmac-sha256";
   92 static unsigned char hmacsha256_offsets[] = { 0, 12 };
   93 static dns_name_t const hmacsha256 = DNS_NAME_INITABSOLUTE(hmacsha256_ndata,
   94                                hmacsha256_offsets);
   95 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256;
   96 
   97 static unsigned char hmacsha384_ndata[] = "\013hmac-sha384";
   98 static unsigned char hmacsha384_offsets[] = { 0, 12 };
   99 static dns_name_t const hmacsha384 = DNS_NAME_INITABSOLUTE(hmacsha384_ndata,
  100                                hmacsha384_offsets);
  101 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384;
  102 
  103 static unsigned char hmacsha512_ndata[] = "\013hmac-sha512";
  104 static unsigned char hmacsha512_offsets[] = { 0, 12 };
  105 static dns_name_t const hmacsha512 = DNS_NAME_INITABSOLUTE(hmacsha512_ndata,
  106                                hmacsha512_offsets);
  107 LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512;
  108 
  109 static const struct {
  110     const dns_name_t *name;
  111     unsigned int dstalg;
  112 } known_algs[] = { { &hmacmd5, DST_ALG_HMACMD5 },
  113            { &gsstsig, DST_ALG_GSSAPI },
  114            { &gsstsigms, DST_ALG_GSSAPI },
  115            { &hmacsha1, DST_ALG_HMACSHA1 },
  116            { &hmacsha224, DST_ALG_HMACSHA224 },
  117            { &hmacsha256, DST_ALG_HMACSHA256 },
  118            { &hmacsha384, DST_ALG_HMACSHA384 },
  119            { &hmacsha512, DST_ALG_HMACSHA512 } };
  120 
  121 static isc_result_t
  122 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
  123 
  124 static void
  125 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
  126     ISC_FORMAT_PRINTF(3, 4);
  127 
  128 static void
  129 cleanup_ring(dns_tsig_keyring_t *ring);
  130 static void
  131 tsigkey_free(dns_tsigkey_t *key);
  132 
  133 bool
  134 dns__tsig_algvalid(unsigned int alg) {
  135     return (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
  136         alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
  137         alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512);
  138 }
  139 
  140 static void
  141 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
  142     va_list ap;
  143     char message[4096];
  144     char namestr[DNS_NAME_FORMATSIZE];
  145     char creatorstr[DNS_NAME_FORMATSIZE];
  146 
  147     if (!isc_log_wouldlog(dns_lctx, level)) {
  148         return;
  149     }
  150     if (key != NULL) {
  151         dns_name_format(&key->name, namestr, sizeof(namestr));
  152     } else {
  153         strlcpy(namestr, "<null>", sizeof(namestr));
  154     }
  155 
  156     if (key != NULL && key->generated && key->creator) {
  157         dns_name_format(key->creator, creatorstr, sizeof(creatorstr));
  158     } else {
  159         strlcpy(creatorstr, "<null>", sizeof(creatorstr));
  160     }
  161 
  162     va_start(ap, fmt);
  163     vsnprintf(message, sizeof(message), fmt, ap);
  164     va_end(ap);
  165     if (key != NULL && key->generated) {
  166         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
  167                   DNS_LOGMODULE_TSIG, level,
  168                   "tsig key '%s' (%s): %s", namestr, creatorstr,
  169                   message);
  170     } else {
  171         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
  172                   DNS_LOGMODULE_TSIG, level, "tsig key '%s': %s",
  173                   namestr, message);
  174     }
  175 }
  176 
  177 static void
  178 remove_fromring(dns_tsigkey_t *tkey) {
  179     if (tkey->generated) {
  180         ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
  181         tkey->ring->generated--;
  182     }
  183     (void)dns_rbt_deletename(tkey->ring->keys, &tkey->name, false);
  184 }
  185 
  186 static void
  187 adjust_lru(dns_tsigkey_t *tkey) {
  188     if (tkey->generated) {
  189         RWLOCK(&tkey->ring->lock, isc_rwlocktype_write);
  190         /*
  191          * We may have been removed from the LRU list between
  192          * removing the read lock and acquiring the write lock.
  193          */
  194         if (ISC_LINK_LINKED(tkey, link) && tkey->ring->lru.tail != tkey)
  195         {
  196             ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
  197             ISC_LIST_APPEND(tkey->ring->lru, tkey, link);
  198         }
  199         RWUNLOCK(&tkey->ring->lock, isc_rwlocktype_write);
  200     }
  201 }
  202 
  203 /*
  204  * A supplemental routine just to add a key to ring.  Note that reference
  205  * counter should be counted separately because we may be adding the key
  206  * as part of creation of the key, in which case the reference counter was
  207  * already initialized.  Also note we don't need RWLOCK for the reference
  208  * counter: it's protected by a separate lock.
  209  */
  210 static isc_result_t
  211 keyring_add(dns_tsig_keyring_t *ring, const dns_name_t *name,
  212         dns_tsigkey_t *tkey) {
  213     isc_result_t result;
  214 
  215     RWLOCK(&ring->lock, isc_rwlocktype_write);
  216     ring->writecount++;
  217 
  218     /*
  219      * Do on the fly cleaning.  Find some nodes we might not
  220      * want around any more.
  221      */
  222     if (ring->writecount > 10) {
  223         cleanup_ring(ring);
  224         ring->writecount = 0;
  225     }
  226 
  227     result = dns_rbt_addname(ring->keys, name, tkey);
  228     if (result == ISC_R_SUCCESS && tkey->generated) {
  229         /*
  230          * Add the new key to the LRU list and remove the least
  231          * recently used key if there are too many keys on the list.
  232          */
  233         ISC_LIST_APPEND(ring->lru, tkey, link);
  234         if (ring->generated++ > ring->maxgenerated) {
  235             remove_fromring(ISC_LIST_HEAD(ring->lru));
  236         }
  237     }
  238     RWUNLOCK(&ring->lock, isc_rwlocktype_write);
  239 
  240     return (result);
  241 }
  242 
  243 isc_result_t
  244 dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm,
  245               dst_key_t *dstkey, bool generated,
  246               const dns_name_t *creator, isc_stdtime_t inception,
  247               isc_stdtime_t expire, isc_mem_t *mctx,
  248               dns_tsig_keyring_t *ring, dns_tsigkey_t **key) {
  249     dns_tsigkey_t *tkey;
  250     isc_result_t ret;
  251     unsigned int refs = 0;
  252     unsigned int dstalg = 0;
  253 
  254     REQUIRE(key == NULL || *key == NULL);
  255     REQUIRE(name != NULL);
  256     REQUIRE(algorithm != NULL);
  257     REQUIRE(mctx != NULL);
  258     REQUIRE(key != NULL || ring != NULL);
  259 
  260     tkey = isc_mem_get(mctx, sizeof(dns_tsigkey_t));
  261 
  262     dns_name_init(&tkey->name, NULL);
  263     dns_name_dup(name, mctx, &tkey->name);
  264     (void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
  265 
  266     /* Check against known algorithm names */
  267     dstalg = dns__tsig_algfromname(algorithm);
  268     if (dstalg != 0) {
  269         /*
  270          * 'algorithm' must be set to a static pointer
  271          * so that dns__tsig_algallocated() can compare them.
  272          */
  273         tkey->algorithm = dns__tsig_algnamefromname(algorithm);
  274         if (dstkey != NULL && dst_key_alg(dstkey) != dstalg) {
  275             ret = DNS_R_BADALG;
  276             goto cleanup_name;
  277         }
  278     } else {
  279         dns_name_t *tmpname;
  280         if (dstkey != NULL) {
  281             ret = DNS_R_BADALG;
  282             goto cleanup_name;
  283         }
  284         tmpname = isc_mem_get(mctx, sizeof(dns_name_t));
  285         dns_name_init(tmpname, NULL);
  286         dns_name_dup(algorithm, mctx, tmpname);
  287         (void)dns_name_downcase(tmpname, tmpname, NULL);
  288         tkey->algorithm = tmpname;
  289     }
  290 
  291     if (creator != NULL) {
  292         tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
  293         dns_name_init(tkey->creator, NULL);
  294         dns_name_dup(creator, mctx, tkey->creator);
  295     } else {
  296         tkey->creator = NULL;
  297     }
  298 
  299     tkey->key = NULL;
  300     if (dstkey != NULL) {
  301         dst_key_attach(dstkey, &tkey->key);
  302     }
  303     tkey->ring = ring;
  304 
  305     if (key != NULL) {
  306         refs = 1;
  307     }
  308     if (ring != NULL) {
  309         refs++;
  310     }
  311 
  312     isc_refcount_init(&tkey->refs, refs);
  313 
  314     tkey->generated = generated;
  315     tkey->inception = inception;
  316     tkey->expire = expire;
  317     tkey->mctx = NULL;
  318     isc_mem_attach(mctx, &tkey->mctx);
  319     ISC_LINK_INIT(tkey, link);
  320 
  321     tkey->magic = TSIG_MAGIC;
  322 
  323     if (ring != NULL) {
  324         ret = keyring_add(ring, name, tkey);
  325         if (ret != ISC_R_SUCCESS) {
  326             goto cleanup_refs;
  327         }
  328     }
  329 
  330     /*
  331      * Ignore this if it's a GSS key, since the key size is meaningless.
  332      */
  333     if (dstkey != NULL && dst_key_size(dstkey) < 64 &&
  334         dstalg != DST_ALG_GSSAPI) {
  335         char namestr[DNS_NAME_FORMATSIZE];
  336         dns_name_format(name, namestr, sizeof(namestr));
  337         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
  338                   DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
  339                   "the key '%s' is too short to be secure",
  340                   namestr);
  341     }
  342 
  343     if (key != NULL) {
  344         *key = tkey;
  345     }
  346 
  347     return (ISC_R_SUCCESS);
  348 
  349 cleanup_refs:
  350     tkey->magic = 0;
  351     while (refs-- > 0) {
  352         isc_refcount_decrement0(&tkey->refs);
  353     }
  354     isc_refcount_destroy(&tkey->refs);
  355 
  356     if (tkey->key != NULL) {
  357         dst_key_free(&tkey->key);
  358     }
  359     if (tkey->creator != NULL) {
  360         dns_name_free(tkey->creator, mctx);
  361         isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
  362     }
  363     if (dns__tsig_algallocated(tkey->algorithm)) {
  364         dns_name_t *tmpname;
  365         DE_CONST(tkey->algorithm, tmpname);
  366         if (dns_name_dynamic(tmpname)) {
  367             dns_name_free(tmpname, mctx);
  368         }
  369         isc_mem_put(mctx, tmpname, sizeof(dns_name_t));
  370     }
  371 cleanup_name:
  372     dns_name_free(&tkey->name, mctx);
  373     isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));
  374 
  375     return (ret);
  376 }
  377 
  378 /*
  379  * Find a few nodes to destroy if possible.
  380  */
  381 static void
  382 cleanup_ring(dns_tsig_keyring_t *ring) {
  383     isc_result_t result;
  384     dns_rbtnodechain_t chain;
  385     dns_name_t foundname;
  386     dns_fixedname_t fixedorigin;
  387     dns_name_t *origin;
  388     isc_stdtime_t now;
  389     dns_rbtnode_t *node;
  390     dns_tsigkey_t *tkey;
  391 
  392     /*
  393      * Start up a new iterator each time.
  394      */
  395     isc_stdtime_get(&now);
  396     dns_name_init(&foundname, NULL);
  397     origin = dns_fixedname_initname(&fixedorigin);
  398 
  399 again:
  400     dns_rbtnodechain_init(&chain);
  401     result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
  402     if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  403         dns_rbtnodechain_invalidate(&chain);
  404         return;
  405     }
  406 
  407     for (;;) {
  408         node = NULL;
  409         dns_rbtnodechain_current(&chain, &foundname, origin, &node);
  410         tkey = node->data;
  411         if (tkey != NULL) {
  412             if (tkey->generated &&
  413                 isc_refcount_current(&tkey->refs) == 1 &&
  414                 tkey->inception != tkey->expire &&
  415                 tkey->expire < now)
  416             {
  417                 tsig_log(tkey, 2, "tsig expire: deleting");
  418                 /* delete the key */
  419                 dns_rbtnodechain_invalidate(&chain);
  420                 remove_fromring(tkey);
  421                 goto again;
  422             }
  423         }
  424         result = dns_rbtnodechain_next(&chain, &foundname, origin);
  425         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  426             dns_rbtnodechain_invalidate(&chain);
  427             return;
  428         }
  429     }
  430 }
  431 
  432 static void
  433 destroyring(dns_tsig_keyring_t *ring) {
  434     isc_refcount_destroy(&ring->references);
  435     dns_rbt_destroy(&ring->keys);
  436     isc_rwlock_destroy(&ring->lock);
  437     isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsig_keyring_t));
  438 }
  439 
  440 /*
  441  * Look up the DST_ALG_ constant for a given name.
  442  */
  443 unsigned int
  444 dns__tsig_algfromname(const dns_name_t *algorithm) {
  445     int i;
  446     int n = sizeof(known_algs) / sizeof(*known_algs);
  447     for (i = 0; i < n; ++i) {
  448         const dns_name_t *name = known_algs[i].name;
  449         if (algorithm == name || dns_name_equal(algorithm, name)) {
  450             return (known_algs[i].dstalg);
  451         }
  452     }
  453     return (0);
  454 }
  455 
  456 /*
  457  * Convert an algorithm name into a pointer to the
  458  * corresponding pre-defined dns_name_t structure.
  459  */
  460 const dns_name_t *
  461 dns__tsig_algnamefromname(const dns_name_t *algorithm) {
  462     int i;
  463     int n = sizeof(known_algs) / sizeof(*known_algs);
  464     for (i = 0; i < n; ++i) {
  465         const dns_name_t *name = known_algs[i].name;
  466         if (algorithm == name || dns_name_equal(algorithm, name)) {
  467             return (name);
  468         }
  469     }
  470     return (NULL);
  471 }
  472 
  473 /*
  474  * Test whether the passed algorithm is NOT a pointer to one of the
  475  * pre-defined known algorithms (and therefore one that has been
  476  * dynamically allocated).
  477  *
  478  * This will return an incorrect result if passed a dynamically allocated
  479  * dns_name_t that happens to match one of the pre-defined names.
  480  */
  481 bool
  482 dns__tsig_algallocated(const dns_name_t *algorithm) {
  483     int i;
  484     int n = sizeof(known_algs) / sizeof(*known_algs);
  485     for (i = 0; i < n; ++i) {
  486         const dns_name_t *name = known_algs[i].name;
  487         if (algorithm == name) {
  488             return (false);
  489         }
  490     }
  491     return (true);
  492 }
  493 
  494 static isc_result_t
  495 restore_key(dns_tsig_keyring_t *ring, isc_stdtime_t now, FILE *fp) {
  496     dst_key_t *dstkey = NULL;
  497     char namestr[1024];
  498     char creatorstr[1024];
  499     char algorithmstr[1024];
  500     char keystr[4096];
  501     unsigned int inception, expire;
  502     int n;
  503     isc_buffer_t b;
  504     dns_name_t *name, *creator, *algorithm;
  505     dns_fixedname_t fname, fcreator, falgorithm;
  506     isc_result_t result;
  507     unsigned int dstalg;
  508 
  509     n = fscanf(fp, "%1023s %1023s %u %u %1023s %4095s\n", namestr,
  510            creatorstr, &inception, &expire, algorithmstr, keystr);
  511     if (n == EOF) {
  512         return (ISC_R_NOMORE);
  513     }
  514     if (n != 6) {
  515         return (ISC_R_FAILURE);
  516     }
  517 
  518     if (isc_serial_lt(expire, now)) {
  519         return (DNS_R_EXPIRED);
  520     }
  521 
  522     name = dns_fixedname_initname(&fname);
  523     isc_buffer_init(&b, namestr, strlen(namestr));
  524     isc_buffer_add(&b, strlen(namestr));
  525     result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
  526     if (result != ISC_R_SUCCESS) {
  527         return (result);
  528     }
  529 
  530     creator = dns_fixedname_initname(&fcreator);
  531     isc_buffer_init(&b, creatorstr, strlen(creatorstr));
  532     isc_buffer_add(&b, strlen(creatorstr));
  533     result = dns_name_fromtext(creator, &b, dns_rootname, 0, NULL);
  534     if (result != ISC_R_SUCCESS) {
  535         return (result);
  536     }
  537 
  538     algorithm = dns_fixedname_initname(&falgorithm);
  539     isc_buffer_init(&b, algorithmstr, strlen(algorithmstr));
  540     isc_buffer_add(&b, strlen(algorithmstr));
  541     result = dns_name_fromtext(algorithm, &b, dns_rootname, 0, NULL);
  542     if (result != ISC_R_SUCCESS) {
  543         return (result);
  544     }
  545 
  546     dstalg = dns__tsig_algfromname(algorithm);
  547     if (dstalg == 0) {
  548         return (DNS_R_BADALG);
  549     }
  550 
  551     result = dst_key_restore(name, dstalg, DNS_KEYOWNER_ENTITY,
  552                  DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
  553                  ring->mctx, keystr, &dstkey);
  554     if (result != ISC_R_SUCCESS) {
  555         return (result);
  556     }
  557 
  558     result = dns_tsigkey_createfromkey(name, algorithm, dstkey, true,
  559                        creator, inception, expire,
  560                        ring->mctx, ring, NULL);
  561     if (dstkey != NULL) {
  562         dst_key_free(&dstkey);
  563     }
  564     return (result);
  565 }
  566 
  567 static void
  568 dump_key(dns_tsigkey_t *tkey, FILE *fp) {
  569     char *buffer = NULL;
  570     int length = 0;
  571     char namestr[DNS_NAME_FORMATSIZE];
  572     char creatorstr[DNS_NAME_FORMATSIZE];
  573     char algorithmstr[DNS_NAME_FORMATSIZE];
  574     isc_result_t result;
  575 
  576     REQUIRE(tkey != NULL);
  577     REQUIRE(fp != NULL);
  578 
  579     dns_name_format(&tkey->name, namestr, sizeof(namestr));
  580     dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr));
  581     dns_name_format(tkey->algorithm, algorithmstr, sizeof(algorithmstr));
  582     result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length);
  583     if (result == ISC_R_SUCCESS) {
  584         fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr,
  585             tkey->inception, tkey->expire, algorithmstr, length,
  586             buffer);
  587     }
  588     if (buffer != NULL) {
  589         isc_mem_put(tkey->mctx, buffer, length);
  590     }
  591 }
  592 
  593 isc_result_t
  594 dns_tsigkeyring_dumpanddetach(dns_tsig_keyring_t **ringp, FILE *fp) {
  595     isc_result_t result;
  596     dns_rbtnodechain_t chain;
  597     dns_name_t foundname;
  598     dns_fixedname_t fixedorigin;
  599     dns_name_t *origin;
  600     isc_stdtime_t now;
  601     dns_rbtnode_t *node;
  602     dns_tsigkey_t *tkey;
  603     dns_tsig_keyring_t *ring;
  604 
  605     REQUIRE(ringp != NULL && *ringp != NULL);
  606 
  607     ring = *ringp;
  608     *ringp = NULL;
  609 
  610     if (isc_refcount_decrement(&ring->references) > 1) {
  611         return (DNS_R_CONTINUE);
  612     }
  613 
  614     isc_stdtime_get(&now);
  615     dns_name_init(&foundname, NULL);
  616     origin = dns_fixedname_initname(&fixedorigin);
  617     dns_rbtnodechain_init(&chain);
  618     result = dns_rbtnodechain_first(&chain, ring->keys, &foundname, origin);
  619     if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  620         dns_rbtnodechain_invalidate(&chain);
  621         goto destroy;
  622     }
  623 
  624     for (;;) {
  625         node = NULL;
  626         dns_rbtnodechain_current(&chain, &foundname, origin, &node);
  627         tkey = node->data;
  628         if (tkey != NULL && tkey->generated && tkey->expire >= now) {
  629             dump_key(tkey, fp);
  630         }
  631         result = dns_rbtnodechain_next(&chain, &foundname, origin);
  632         if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
  633             dns_rbtnodechain_invalidate(&chain);
  634             if (result == ISC_R_NOMORE) {
  635                 result = ISC_R_SUCCESS;
  636             }
  637             goto destroy;
  638         }
  639     }
  640 
  641 destroy:
  642     destroyring(ring);
  643     return (result);
  644 }
  645 
  646 const dns_name_t *
  647 dns_tsigkey_identity(const dns_tsigkey_t *tsigkey) {
  648     REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
  649 
  650     if (tsigkey == NULL) {
  651         return (NULL);
  652     }
  653     if (tsigkey->generated) {
  654         return (tsigkey->creator);
  655     } else {
  656         return (&tsigkey->name);
  657     }
  658 }
  659 
  660 isc_result_t
  661 dns_tsigkey_create(const dns_name_t *name, const dns_name_t *algorithm,
  662            unsigned char *secret, int length, bool generated,
  663            const dns_name_t *creator, isc_stdtime_t inception,
  664            isc_stdtime_t expire, isc_mem_t *mctx,
  665            dns_tsig_keyring_t *ring, dns_tsigkey_t **key) {
  666     dst_key_t *dstkey = NULL;
  667     isc_result_t result;
  668     unsigned int dstalg = 0;
  669 
  670     REQUIRE(length >= 0);
  671     if (length > 0) {
  672         REQUIRE(secret != NULL);
  673     }
  674 
  675     dstalg = dns__tsig_algfromname(algorithm);
  676     if (dns__tsig_algvalid(dstalg)) {
  677         if (secret != NULL) {
  678             isc_buffer_t b;
  679 
  680             isc_buffer_init(&b, secret, length);
  681             isc_buffer_add(&b, length);
  682             result = dst_key_frombuffer(
  683                 name, dstalg, DNS_KEYOWNER_ENTITY,
  684                 DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, &b,
  685                 mctx, &dstkey);
  686             if (result != ISC_R_SUCCESS) {
  687                 return (result);
  688             }
  689         }
  690     } else if (length > 0) {
  691         return (DNS_R_BADALG);
  692     }
  693 
  694     result = dns_tsigkey_createfromkey(name, algorithm, dstkey, generated,
  695                        creator, inception, expire, mctx,
  696                        ring, key);
  697     if (dstkey != NULL) {
  698         dst_key_free(&dstkey);
  699     }
  700     return (result);
  701 }
  702 
  703 void
  704 dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp) {
  705     REQUIRE(VALID_TSIG_KEY(source));
  706     REQUIRE(targetp != NULL && *targetp == NULL);
  707 
  708     isc_refcount_increment(&source->refs);
  709     *targetp = source;
  710 }
  711 
  712 static void
  713 tsigkey_free(dns_tsigkey_t *key) {
  714     REQUIRE(VALID_TSIG_KEY(key));
  715 
  716     key->magic = 0;
  717     dns_name_free(&key->name, key->mctx);
  718     if (dns__tsig_algallocated(key->algorithm)) {
  719         dns_name_t *name;
  720         DE_CONST(key->algorithm, name);
  721         dns_name_free(name, key->mctx);
  722         isc_mem_put(key->mctx, name, sizeof(dns_name_t));
  723     }
  724     if (key->key != NULL) {
  725         dst_key_free(&key->key);
  726     }
  727     if (key->creator != NULL) {
  728         dns_name_free(key->creator, key->mctx);
  729         isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
  730     }
  731     isc_mem_putanddetach(&key->mctx, key, sizeof(dns_tsigkey_t));
  732 }
  733 
  734 void
  735 dns_tsigkey_detach(dns_tsigkey_t **keyp) {
  736     REQUIRE(keyp != NULL && VALID_TSIG_KEY(*keyp));
  737     dns_tsigkey_t *key = *keyp;
  738     *keyp = NULL;
  739 
  740     if (isc_refcount_decrement(&key->refs) == 1) {
  741         isc_refcount_destroy(&key->refs);
  742         tsigkey_free(key);
  743     }
  744 }
  745 
  746 void
  747 dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
  748     REQUIRE(VALID_TSIG_KEY(key));
  749     REQUIRE(key->ring != NULL);
  750 
  751     RWLOCK(&key->ring->lock, isc_rwlocktype_write);
  752     remove_fromring(key);
  753     RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
  754 }
  755 
  756 isc_result_t
  757 dns_tsig_sign(dns_message_t *msg) {
  758     dns_tsigkey_t *key = NULL;
  759     dns_rdata_any_tsig_t tsig, querytsig;
  760     unsigned char data[128];
  761     isc_buffer_t databuf, sigbuf;
  762     isc_buffer_t *dynbuf = NULL;
  763     dns_name_t *owner;
  764     dns_rdata_t *rdata = NULL;
  765     dns_rdatalist_t *datalist = NULL;
  766     dns_rdataset_t *dataset = NULL;
  767     isc_region_t r;
  768     isc_stdtime_t now;
  769     isc_mem_t *mctx;
  770     dst_context_t *ctx = NULL;
  771     isc_result_t ret;
  772     unsigned char badtimedata[BADTIMELEN];
  773     unsigned int sigsize = 0;
  774     bool response;
  775 
  776     REQUIRE(msg != NULL);
  777     key = dns_message_gettsigkey(msg);
  778     REQUIRE(VALID_TSIG_KEY(key));
  779 
  780     /*
  781      * If this is a response, there should be a TSIG in the query with the
  782      * the exception if this is a TKEY request (see RFC 3645, Section 2.2).
  783      */
  784     response = is_response(msg);
  785     if (response && msg->querytsig == NULL) {
  786         if (msg->tkey != 1) {
  787             return (DNS_R_EXPECTEDTSIG);
  788         }
  789     }
  790 
  791     mctx = msg->mctx;
  792 
  793     tsig.mctx = mctx;
  794     tsig.common.rdclass = dns_rdataclass_any;
  795     tsig.common.rdtype = dns_rdatatype_tsig;
  796     ISC_LINK_INIT(&tsig.common, link);
  797     dns_name_init(&tsig.algorithm, NULL);
  798     dns_name_clone(key->algorithm, &tsig.algorithm);
  799 
  800     isc_stdtime_get(&now);
  801     tsig.timesigned = now + msg->timeadjust;
  802     tsig.fudge = DNS_TSIG_FUDGE;
  803 
  804     tsig.originalid = msg->id;
  805 
  806     isc_buffer_init(&databuf, data, sizeof(data));
  807 
  808     if (response) {
  809         tsig.error = msg->querytsigstatus;
  810     } else {
  811         tsig.error = dns_rcode_noerror;
  812     }
  813 
  814     if (tsig.error != dns_tsigerror_badtime) {
  815         tsig.otherlen = 0;
  816         tsig.other = NULL;
  817     } else {
  818         isc_buffer_t otherbuf;
  819 
  820         tsig.otherlen = BADTIMELEN;
  821         tsig.other = badtimedata;
  822         isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
  823         isc_buffer_putuint48(&otherbuf, tsig.timesigned);
  824     }
  825 
  826     if ((key->key != NULL) && (tsig.error != dns_tsigerror_badsig) &&
  827         (tsig.error != dns_tsigerror_badkey))
  828     {
  829         unsigned char header[DNS_MESSAGE_HEADERLEN];
  830         isc_buffer_t headerbuf;
  831         uint16_t digestbits;
  832         bool querytsig_ok = false;
  833 
  834         /*
  835          * If it is a response, we assume that the request MAC
  836          * has validated at this point. This is why we include a
  837          * MAC length > 0 in the reply.
  838          */
  839         ret = dst_context_create(key->key, mctx, DNS_LOGCATEGORY_DNSSEC,
  840                      true, 0, &ctx);
  841         if (ret != ISC_R_SUCCESS) {
  842             return (ret);
  843         }
  844 
  845         /*
  846          * If this is a response, and if there was a TSIG in
  847          * the query, digest the request's MAC.
  848          *
  849          * (Note: querytsig should be non-NULL for all
  850          * responses except TKEY responses. Those may be signed
  851          * with the newly-negotiated TSIG key even if the query
  852          * wasn't signed.)
  853          */
  854         if (response && msg->querytsig != NULL) {
  855             dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
  856 
  857             INSIST(msg->verified_sig);
  858 
  859             ret = dns_rdataset_first(msg->querytsig);
  860             if (ret != ISC_R_SUCCESS) {
  861                 goto cleanup_context;
  862             }
  863             dns_rdataset_current(msg->querytsig, &querytsigrdata);
  864             ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
  865                          NULL);
  866             if (ret != ISC_R_SUCCESS) {
  867                 goto cleanup_context;
  868             }
  869             isc_buffer_putuint16(&databuf, querytsig.siglen);
  870             if (isc_buffer_availablelength(&databuf) <
  871                 querytsig.siglen) {
  872                 ret = ISC_R_NOSPACE;
  873                 goto cleanup_context;
  874             }
  875             isc_buffer_putmem(&databuf, querytsig.signature,
  876                       querytsig.siglen);
  877             isc_buffer_usedregion(&databuf, &r);
  878             ret = dst_context_adddata(ctx, &r);
  879             if (ret != ISC_R_SUCCESS) {
  880                 goto cleanup_context;
  881             }
  882             querytsig_ok = true;
  883         }
  884 
  885         /*
  886          * Digest the header.
  887          */
  888         isc_buffer_init(&headerbuf, header, sizeof(header));
  889         dns_message_renderheader(msg, &headerbuf);
  890         isc_buffer_usedregion(&headerbuf, &r);
  891         ret = dst_context_adddata(ctx, &r);
  892         if (ret != ISC_R_SUCCESS) {
  893             goto cleanup_context;
  894         }
  895 
  896         /*
  897          * Digest the remainder of the message.
  898          */
  899         isc_buffer_usedregion(msg->buffer, &r);
  900         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
  901         ret = dst_context_adddata(ctx, &r);
  902         if (ret != ISC_R_SUCCESS) {
  903             goto cleanup_context;
  904         }
  905 
  906         if (msg->tcp_continuation == 0) {
  907             /*
  908              * Digest the name, class, ttl, alg.
  909              */
  910             dns_name_toregion(&key->name, &r);
  911             ret = dst_context_adddata(ctx, &r);
  912             if (ret != ISC_R_SUCCESS) {
  913                 goto cleanup_context;
  914             }
  915 
  916             isc_buffer_clear(&databuf);
  917             isc_buffer_putuint16(&databuf, dns_rdataclass_any);
  918             isc_buffer_putuint32(&databuf, 0); /* ttl */
  919             isc_buffer_usedregion(&databuf, &r);
  920             ret = dst_context_adddata(ctx, &r);
  921             if (ret != ISC_R_SUCCESS) {
  922                 goto cleanup_context;
  923             }
  924 
  925             dns_name_toregion(&tsig.algorithm, &r);
  926             ret = dst_context_adddata(ctx, &r);
  927             if (ret != ISC_R_SUCCESS) {
  928                 goto cleanup_context;
  929             }
  930         }
  931         /* Digest the timesigned and fudge */
  932         isc_buffer_clear(&databuf);
  933         if (tsig.error == dns_tsigerror_badtime && querytsig_ok) {
  934             tsig.timesigned = querytsig.timesigned;
  935         }
  936         isc_buffer_putuint48(&databuf, tsig.timesigned);
  937         isc_buffer_putuint16(&databuf, tsig.fudge);
  938         isc_buffer_usedregion(&databuf, &r);
  939         ret = dst_context_adddata(ctx, &r);
  940         if (ret != ISC_R_SUCCESS) {
  941             goto cleanup_context;
  942         }
  943 
  944         if (msg->tcp_continuation == 0) {
  945             /*
  946              * Digest the error and other data length.
  947              */
  948             isc_buffer_clear(&databuf);
  949             isc_buffer_putuint16(&databuf, tsig.error);
  950             isc_buffer_putuint16(&databuf, tsig.otherlen);
  951 
  952             isc_buffer_usedregion(&databuf, &r);
  953             ret = dst_context_adddata(ctx, &r);
  954             if (ret != ISC_R_SUCCESS) {
  955                 goto cleanup_context;
  956             }
  957 
  958             /*
  959              * Digest other data.
  960              */
  961             if (tsig.otherlen > 0) {
  962                 r.length = tsig.otherlen;
  963                 r.base = tsig.other;
  964                 ret = dst_context_adddata(ctx, &r);
  965                 if (ret != ISC_R_SUCCESS) {
  966                     goto cleanup_context;
  967                 }
  968             }
  969         }
  970 
  971         ret = dst_key_sigsize(key->key, &sigsize);
  972         if (ret != ISC_R_SUCCESS) {
  973             goto cleanup_context;
  974         }
  975         tsig.signature = isc_mem_get(mctx, sigsize);
  976 
  977         isc_buffer_init(&sigbuf, tsig.signature, sigsize);
  978         ret = dst_context_sign(ctx, &sigbuf);
  979         if (ret != ISC_R_SUCCESS) {
  980             goto cleanup_signature;
  981         }
  982         dst_context_destroy(&ctx);
  983         digestbits = dst_key_getbits(key->key);
  984         if (digestbits != 0) {
  985             unsigned int bytes = (digestbits + 7) / 8;
  986             if (querytsig_ok && bytes < querytsig.siglen) {
  987                 bytes = querytsig.siglen;
  988             }
  989             if (bytes > isc_buffer_usedlength(&sigbuf)) {
  990                 bytes = isc_buffer_usedlength(&sigbuf);
  991             }
  992             tsig.siglen = bytes;
  993         } else {
  994             tsig.siglen = isc_buffer_usedlength(&sigbuf);
  995         }
  996     } else {
  997         tsig.siglen = 0;
  998         tsig.signature = NULL;
  999     }
 1000 
 1001     ret = dns_message_gettemprdata(msg, &rdata);
 1002     if (ret != ISC_R_SUCCESS) {
 1003         goto cleanup_signature;
 1004     }
 1005     isc_buffer_allocate(msg->mctx, &dynbuf, 512);
 1006     ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
 1007                    dns_rdatatype_tsig, &tsig, dynbuf);
 1008     if (ret != ISC_R_SUCCESS) {
 1009         goto cleanup_dynbuf;
 1010     }
 1011 
 1012     dns_message_takebuffer(msg, &dynbuf);
 1013 
 1014     if (tsig.signature != NULL) {
 1015         isc_mem_put(mctx, tsig.signature, sigsize);
 1016         tsig.signature = NULL;
 1017     }
 1018 
 1019     owner = NULL;
 1020     ret = dns_message_gettempname(msg, &owner);
 1021     if (ret != ISC_R_SUCCESS) {
 1022         goto cleanup_rdata;
 1023     }
 1024     dns_name_init(owner, NULL);
 1025     dns_name_dup(&key->name, msg->mctx, owner);
 1026 
 1027     datalist = NULL;
 1028     ret = dns_message_gettemprdatalist(msg, &datalist);
 1029     if (ret != ISC_R_SUCCESS) {
 1030         goto cleanup_owner;
 1031     }
 1032     dataset = NULL;
 1033     ret = dns_message_gettemprdataset(msg, &dataset);
 1034     if (ret != ISC_R_SUCCESS) {
 1035         goto cleanup_rdatalist;
 1036     }
 1037     datalist->rdclass = dns_rdataclass_any;
 1038     datalist->type = dns_rdatatype_tsig;
 1039     ISC_LIST_APPEND(datalist->rdata, rdata, link);
 1040     RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) ==
 1041               ISC_R_SUCCESS);
 1042     msg->tsig = dataset;
 1043     msg->tsigname = owner;
 1044 
 1045     /* Windows does not like the tsig name being compressed. */
 1046     msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
 1047 
 1048     return (ISC_R_SUCCESS);
 1049 
 1050 cleanup_rdatalist:
 1051     dns_message_puttemprdatalist(msg, &datalist);
 1052 cleanup_owner:
 1053     dns_message_puttempname(msg, &owner);
 1054     goto cleanup_rdata;
 1055 cleanup_dynbuf:
 1056     isc_buffer_free(&dynbuf);
 1057 cleanup_rdata:
 1058     dns_message_puttemprdata(msg, &rdata);
 1059 cleanup_signature:
 1060     if (tsig.signature != NULL) {
 1061         isc_mem_put(mctx, tsig.signature, sigsize);
 1062     }
 1063 cleanup_context:
 1064     if (ctx != NULL) {
 1065         dst_context_destroy(&ctx);
 1066     }
 1067     return (ret);
 1068 }
 1069 
 1070 isc_result_t
 1071 dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
 1072         dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2) {
 1073     dns_rdata_any_tsig_t tsig, querytsig;
 1074     isc_region_t r, source_r, header_r, sig_r;
 1075     isc_buffer_t databuf;
 1076     unsigned char data[32];
 1077     dns_name_t *keyname;
 1078     dns_rdata_t rdata = DNS_RDATA_INIT;
 1079     isc_stdtime_t now;
 1080     isc_result_t ret;
 1081     dns_tsigkey_t *tsigkey;
 1082     dst_key_t *key = NULL;
 1083     unsigned char header[DNS_MESSAGE_HEADERLEN];
 1084     dst_context_t *ctx = NULL;
 1085     isc_mem_t *mctx;
 1086     uint16_t addcount, id;
 1087     unsigned int siglen;
 1088     unsigned int alg;
 1089     bool response;
 1090 
 1091     REQUIRE(source != NULL);
 1092     REQUIRE(DNS_MESSAGE_VALID(msg));
 1093     tsigkey = dns_message_gettsigkey(msg);
 1094     response = is_response(msg);
 1095 
 1096     REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
 1097 
 1098     msg->verify_attempted = 1;
 1099     msg->verified_sig = 0;
 1100     msg->tsigstatus = dns_tsigerror_badsig;
 1101 
 1102     if (msg->tcp_continuation) {
 1103         if (tsigkey == NULL || msg->querytsig == NULL) {
 1104             return (DNS_R_UNEXPECTEDTSIG);
 1105         }
 1106         return (tsig_verify_tcp(source, msg));
 1107     }
 1108 
 1109     /*
 1110      * There should be a TSIG record...
 1111      */
 1112     if (msg->tsig == NULL) {
 1113         return (DNS_R_EXPECTEDTSIG);
 1114     }
 1115 
 1116     /*
 1117      * If this is a response and there's no key or query TSIG, there
 1118      * shouldn't be one on the response.
 1119      */
 1120     if (response && (tsigkey == NULL || msg->querytsig == NULL)) {
 1121         return (DNS_R_UNEXPECTEDTSIG);
 1122     }
 1123 
 1124     mctx = msg->mctx;
 1125 
 1126     /*
 1127      * If we're here, we know the message is well formed and contains a
 1128      * TSIG record.
 1129      */
 1130 
 1131     keyname = msg->tsigname;
 1132     ret = dns_rdataset_first(msg->tsig);
 1133     if (ret != ISC_R_SUCCESS) {
 1134         return (ret);
 1135     }
 1136     dns_rdataset_current(msg->tsig, &rdata);
 1137     ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
 1138     if (ret != ISC_R_SUCCESS) {
 1139         return (ret);
 1140     }
 1141     dns_rdata_reset(&rdata);
 1142     if (response) {
 1143         ret = dns_rdataset_first(msg->querytsig);
 1144         if (ret != ISC_R_SUCCESS) {
 1145             return (ret);
 1146         }
 1147         dns_rdataset_current(msg->querytsig, &rdata);
 1148         ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
 1149         if (ret != ISC_R_SUCCESS) {
 1150             return (ret);
 1151         }
 1152     }
 1153 #if defined(__clang__) && (__clang_major__ < 3 ||                           \
 1154                (__clang_major__ == 3 && __clang_minor__ < 2) || \
 1155                (__clang_major__ == 4 && __clang_minor__ < 2))
 1156     /* false positive: http://llvm.org/bugs/show_bug.cgi?id=14461 */
 1157     else
 1158     {
 1159         memset(&querytsig, 0, sizeof(querytsig));
 1160     }
 1161 #endif /* if defined(__clang__) && (__clang_major__ < 3 || (__clang_major__ == \
 1162     * 3                                                                    \
 1163     * && __clang_minor__ < 2) || (__clang_major__ == 4 && __clang_minor__  \
 1164     * < 2)) */
 1165 
 1166     /*
 1167      * Do the key name and algorithm match that of the query?
 1168      */
 1169     if (response &&
 1170         (!dns_name_equal(keyname, &tsigkey->name) ||
 1171          !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
 1172     {
 1173         msg->tsigstatus = dns_tsigerror_badkey;
 1174         tsig_log(msg->tsigkey, 2,
 1175              "key name and algorithm do not match");
 1176         return (DNS_R_TSIGVERIFYFAILURE);
 1177     }
 1178 
 1179     /*
 1180      * Get the current time.
 1181      */
 1182     isc_stdtime_get(&now);
 1183 
 1184     /*
 1185      * Find dns_tsigkey_t based on keyname.
 1186      */
 1187     if (tsigkey == NULL) {
 1188         ret = ISC_R_NOTFOUND;
 1189         if (ring1 != NULL) {
 1190             ret = dns_tsigkey_find(&tsigkey, keyname,
 1191                            &tsig.algorithm, ring1);
 1192         }
 1193         if (ret == ISC_R_NOTFOUND && ring2 != NULL) {
 1194             ret = dns_tsigkey_find(&tsigkey, keyname,
 1195                            &tsig.algorithm, ring2);
 1196         }
 1197         if (ret != ISC_R_SUCCESS) {
 1198             msg->tsigstatus = dns_tsigerror_badkey;
 1199             ret = dns_tsigkey_create(keyname, &tsig.algorithm, NULL,
 1200                          0, false, NULL, now, now, mctx,
 1201                          NULL, &msg->tsigkey);
 1202             if (ret != ISC_R_SUCCESS) {
 1203                 return (ret);
 1204             }
 1205             tsig_log(msg->tsigkey, 2, "unknown key");
 1206             return (DNS_R_TSIGVERIFYFAILURE);
 1207         }
 1208         msg->tsigkey = tsigkey;
 1209     }
 1210 
 1211     key = tsigkey->key;
 1212 
 1213     /*
 1214      * Check digest length.
 1215      */
 1216     alg = dst_key_alg(key);
 1217     ret = dst_key_sigsize(key, &siglen);
 1218     if (ret != ISC_R_SUCCESS) {
 1219         return (ret);
 1220     }
 1221     if (dns__tsig_algvalid(alg)) {
 1222         if (tsig.siglen > siglen) {
 1223             tsig_log(msg->tsigkey, 2, "signature length too big");
 1224             return (DNS_R_FORMERR);
 1225         }
 1226         if (tsig.siglen > 0 &&
 1227             (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) {
 1228             tsig_log(msg->tsigkey, 2,
 1229                  "signature length below minimum");
 1230             return (DNS_R_FORMERR);
 1231         }
 1232     }
 1233 
 1234     if (tsig.siglen > 0) {
 1235         uint16_t addcount_n;
 1236 
 1237         sig_r.base = tsig.signature;
 1238         sig_r.length = tsig.siglen;
 1239 
 1240         ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC,
 1241                      false, 0, &ctx);
 1242         if (ret != ISC_R_SUCCESS) {
 1243             return (ret);
 1244         }
 1245 
 1246         if (response) {
 1247             isc_buffer_init(&databuf, data, sizeof(data));
 1248             isc_buffer_putuint16(&databuf, querytsig.siglen);
 1249             isc_buffer_usedregion(&databuf, &r);
 1250             ret = dst_context_adddata(ctx, &r);
 1251             if (ret != ISC_R_SUCCESS) {
 1252                 goto cleanup_context;
 1253             }
 1254             if (querytsig.siglen > 0) {
 1255                 r.length = querytsig.siglen;
 1256                 r.base = querytsig.signature;
 1257                 ret = dst_context_adddata(ctx, &r);
 1258                 if (ret != ISC_R_SUCCESS) {
 1259                     goto cleanup_context;
 1260                 }
 1261             }
 1262         }
 1263 
 1264         /*
 1265          * Extract the header.
 1266          */
 1267         isc_buffer_usedregion(source, &r);
 1268         memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
 1269         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
 1270 
 1271         /*
 1272          * Decrement the additional field counter.
 1273          */
 1274         memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
 1275         addcount_n = ntohs(addcount);
 1276         addcount = htons((uint16_t)(addcount_n - 1));
 1277         memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
 1278 
 1279         /*
 1280          * Put in the original id.
 1281          */
 1282         id = htons(tsig.originalid);
 1283         memmove(&header[0], &id, 2);
 1284 
 1285         /*
 1286          * Digest the modified header.
 1287          */
 1288         header_r.base = (unsigned char *)header;
 1289         header_r.length = DNS_MESSAGE_HEADERLEN;
 1290         ret = dst_context_adddata(ctx, &header_r);
 1291         if (ret != ISC_R_SUCCESS) {
 1292             goto cleanup_context;
 1293         }
 1294 
 1295         /*
 1296          * Digest all non-TSIG records.
 1297          */
 1298         isc_buffer_usedregion(source, &source_r);
 1299         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
 1300         r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
 1301         ret = dst_context_adddata(ctx, &r);
 1302         if (ret != ISC_R_SUCCESS) {
 1303             goto cleanup_context;
 1304         }
 1305 
 1306         /*
 1307          * Digest the key name.
 1308          */
 1309         dns_name_toregion(&tsigkey->name, &r);
 1310         ret = dst_context_adddata(ctx, &r);
 1311         if (ret != ISC_R_SUCCESS) {
 1312             goto cleanup_context;
 1313         }
 1314 
 1315         isc_buffer_init(&databuf, data, sizeof(data));
 1316         isc_buffer_putuint16(&databuf, tsig.common.rdclass);
 1317         isc_buffer_putuint32(&databuf, msg->tsig->ttl);
 1318         isc_buffer_usedregion(&databuf, &r);
 1319         ret = dst_context_adddata(ctx, &r);
 1320         if (ret != ISC_R_SUCCESS) {
 1321             goto cleanup_context;
 1322         }
 1323 
 1324         /*
 1325          * Digest the key algorithm.
 1326          */
 1327         dns_name_toregion(tsigkey->algorithm, &r);
 1328         ret = dst_context_adddata(ctx, &r);
 1329         if (ret != ISC_R_SUCCESS) {
 1330             goto cleanup_context;
 1331         }
 1332 
 1333         isc_buffer_clear(&databuf);
 1334         isc_buffer_putuint48(&databuf, tsig.timesigned);
 1335         isc_buffer_putuint16(&databuf, tsig.fudge);
 1336         isc_buffer_putuint16(&databuf, tsig.error);
 1337         isc_buffer_putuint16(&databuf, tsig.otherlen);
 1338         isc_buffer_usedregion(&databuf, &r);
 1339         ret = dst_context_adddata(ctx, &r);
 1340         if (ret != ISC_R_SUCCESS) {
 1341             goto cleanup_context;
 1342         }
 1343 
 1344         if (tsig.otherlen > 0) {
 1345             r.base = tsig.other;
 1346             r.length = tsig.otherlen;
 1347             ret = dst_context_adddata(ctx, &r);
 1348             if (ret != ISC_R_SUCCESS) {
 1349                 goto cleanup_context;
 1350             }
 1351         }
 1352 
 1353         ret = dst_context_verify(ctx, &sig_r);
 1354         if (ret == DST_R_VERIFYFAILURE) {
 1355             ret = DNS_R_TSIGVERIFYFAILURE;
 1356             tsig_log(msg->tsigkey, 2,
 1357                  "signature failed to verify(1)");
 1358             goto cleanup_context;
 1359         } else if (ret != ISC_R_SUCCESS) {
 1360             goto cleanup_context;
 1361         }
 1362         msg->verified_sig = 1;
 1363     } else if (!response || (tsig.error != dns_tsigerror_badsig &&
 1364                  tsig.error != dns_tsigerror_badkey))
 1365     {
 1366         tsig_log(msg->tsigkey, 2, "signature was empty");
 1367         return (DNS_R_TSIGVERIFYFAILURE);
 1368     }
 1369 
 1370     /*
 1371      * Here at this point, the MAC has been verified. Even if any of
 1372      * the following code returns a TSIG error, the reply will be
 1373      * signed and WILL always include the request MAC in the digest
 1374      * computation.
 1375      */
 1376 
 1377     /*
 1378      * Is the time ok?
 1379      */
 1380     if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
 1381         msg->tsigstatus = dns_tsigerror_badtime;
 1382         tsig_log(msg->tsigkey, 2, "signature has expired");
 1383         ret = DNS_R_CLOCKSKEW;
 1384         goto cleanup_context;
 1385     } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
 1386         msg->tsigstatus = dns_tsigerror_badtime;
 1387         tsig_log(msg->tsigkey, 2, "signature is in the future");
 1388         ret = DNS_R_CLOCKSKEW;
 1389         goto cleanup_context;
 1390     }
 1391 
 1392     if (dns__tsig_algvalid(alg)) {
 1393         uint16_t digestbits = dst_key_getbits(key);
 1394 
 1395         if (tsig.siglen > 0 && digestbits != 0 &&
 1396             tsig.siglen < ((digestbits + 7) / 8)) {
 1397             msg->tsigstatus = dns_tsigerror_badtrunc;
 1398             tsig_log(msg->tsigkey, 2,
 1399                  "truncated signature length too small");
 1400             ret = DNS_R_TSIGVERIFYFAILURE;
 1401             goto cleanup_context;
 1402         }
 1403         if (tsig.siglen > 0 && digestbits == 0 && tsig.siglen < siglen)
 1404         {
 1405             msg->tsigstatus = dns_tsigerror_badtrunc;
 1406             tsig_log(msg->tsigkey, 2, "signature length too small");
 1407             ret = DNS_R_TSIGVERIFYFAILURE;
 1408             goto cleanup_context;
 1409         }
 1410     }
 1411 
 1412     if (response && tsig.error != dns_rcode_noerror) {
 1413         msg->tsigstatus = tsig.error;
 1414         if (tsig.error == dns_tsigerror_badtime) {
 1415             ret = DNS_R_CLOCKSKEW;
 1416         } else {
 1417             ret = DNS_R_TSIGERRORSET;
 1418         }
 1419         goto cleanup_context;
 1420     }
 1421 
 1422     msg->tsigstatus = dns_rcode_noerror;
 1423     ret = ISC_R_SUCCESS;
 1424 
 1425 cleanup_context:
 1426     if (ctx != NULL) {
 1427         dst_context_destroy(&ctx);
 1428     }
 1429 
 1430     return (ret);
 1431 }
 1432 
 1433 static isc_result_t
 1434 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
 1435     dns_rdata_any_tsig_t tsig, querytsig;
 1436     isc_region_t r, source_r, header_r, sig_r;
 1437     isc_buffer_t databuf;
 1438     unsigned char data[32];
 1439     dns_name_t *keyname;
 1440     dns_rdata_t rdata = DNS_RDATA_INIT;
 1441     isc_stdtime_t now;
 1442     isc_result_t ret;
 1443     dns_tsigkey_t *tsigkey;
 1444     dst_key_t *key = NULL;
 1445     unsigned char header[DNS_MESSAGE_HEADERLEN];
 1446     uint16_t addcount, id;
 1447     bool has_tsig = false;
 1448     isc_mem_t *mctx;
 1449     unsigned int siglen;
 1450     unsigned int alg;
 1451 
 1452     REQUIRE(source != NULL);
 1453     REQUIRE(msg != NULL);
 1454     REQUIRE(dns_message_gettsigkey(msg) != NULL);
 1455     REQUIRE(msg->tcp_continuation == 1);
 1456     REQUIRE(msg->querytsig != NULL);
 1457 
 1458     msg->verified_sig = 0;
 1459     msg->tsigstatus = dns_tsigerror_badsig;
 1460 
 1461     if (!is_response(msg)) {
 1462         return (DNS_R_EXPECTEDRESPONSE);
 1463     }
 1464 
 1465     mctx = msg->mctx;
 1466 
 1467     tsigkey = dns_message_gettsigkey(msg);
 1468     key = tsigkey->key;
 1469 
 1470     /*
 1471      * Extract and parse the previous TSIG
 1472      */
 1473     ret = dns_rdataset_first(msg->querytsig);
 1474     if (ret != ISC_R_SUCCESS) {
 1475         return (ret);
 1476     }
 1477     dns_rdataset_current(msg->querytsig, &rdata);
 1478     ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
 1479     if (ret != ISC_R_SUCCESS) {
 1480         return (ret);
 1481     }
 1482     dns_rdata_reset(&rdata);
 1483 
 1484     /*
 1485      * If there is a TSIG in this message, do some checks.
 1486      */
 1487     if (msg->tsig != NULL) {
 1488         has_tsig = true;
 1489 
 1490         keyname = msg->tsigname;
 1491         ret = dns_rdataset_first(msg->tsig);
 1492         if (ret != ISC_R_SUCCESS) {
 1493             goto cleanup_querystruct;
 1494         }
 1495         dns_rdataset_current(msg->tsig, &rdata);
 1496         ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
 1497         if (ret != ISC_R_SUCCESS) {
 1498             goto cleanup_querystruct;
 1499         }
 1500 
 1501         /*
 1502          * Do the key name and algorithm match that of the query?
 1503          */
 1504         if (!dns_name_equal(keyname, &tsigkey->name) ||
 1505             !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
 1506         {
 1507             msg->tsigstatus = dns_tsigerror_badkey;
 1508             ret = DNS_R_TSIGVERIFYFAILURE;
 1509             tsig_log(msg->tsigkey, 2,
 1510                  "key name and algorithm do not match");
 1511             goto cleanup_querystruct;
 1512         }
 1513 
 1514         /*
 1515          * Check digest length.
 1516          */
 1517         alg = dst_key_alg(key);
 1518         ret = dst_key_sigsize(key, &siglen);
 1519         if (ret != ISC_R_SUCCESS) {
 1520             goto cleanup_querystruct;
 1521         }
 1522         if (dns__tsig_algvalid(alg)) {
 1523             if (tsig.siglen > siglen) {
 1524                 tsig_log(tsigkey, 2,
 1525                      "signature length too big");
 1526                 ret = DNS_R_FORMERR;
 1527                 goto cleanup_querystruct;
 1528             }
 1529             if (tsig.siglen > 0 &&
 1530                 (tsig.siglen < 10 ||
 1531                  tsig.siglen < ((siglen + 1) / 2))) {
 1532                 tsig_log(tsigkey, 2,
 1533                      "signature length below minimum");
 1534                 ret = DNS_R_FORMERR;
 1535                 goto cleanup_querystruct;
 1536             }
 1537         }
 1538     }
 1539 
 1540     if (msg->tsigctx == NULL) {
 1541         ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC,
 1542                      false, 0, &msg->tsigctx);
 1543         if (ret != ISC_R_SUCCESS) {
 1544             goto cleanup_querystruct;
 1545         }
 1546 
 1547         /*
 1548          * Digest the length of the query signature
 1549          */
 1550         isc_buffer_init(&databuf, data, sizeof(data));
 1551         isc_buffer_putuint16(&databuf, querytsig.siglen);
 1552         isc_buffer_usedregion(&databuf, &r);
 1553         ret = dst_context_adddata(msg->tsigctx, &r);
 1554         if (ret != ISC_R_SUCCESS) {
 1555             goto cleanup_context;
 1556         }
 1557 
 1558         /*
 1559          * Digest the data of the query signature
 1560          */
 1561         if (querytsig.siglen > 0) {
 1562             r.length = querytsig.siglen;
 1563             r.base = querytsig.signature;
 1564             ret = dst_context_adddata(msg->tsigctx, &r);
 1565             if (ret != ISC_R_SUCCESS) {
 1566                 goto cleanup_context;
 1567             }
 1568         }
 1569     }
 1570 
 1571     /*
 1572      * Extract the header.
 1573      */
 1574     isc_buffer_usedregion(source, &r);
 1575     memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
 1576     isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
 1577 
 1578     /*
 1579      * Decrement the additional field counter if necessary.
 1580      */
 1581     if (has_tsig) {
 1582         uint16_t addcount_n;
 1583 
 1584         memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
 1585         addcount_n = ntohs(addcount);
 1586         addcount = htons((uint16_t)(addcount_n - 1));
 1587         memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
 1588 
 1589         /*
 1590          * Put in the original id.
 1591          *
 1592          * XXX Can TCP transfers be forwarded?  How would that
 1593          * work?
 1594          */
 1595         /* cppcheck-suppress uninitStructMember
 1596          * symbolName=tsig.originalid */
 1597         id = htons(tsig.originalid);
 1598         memmove(&header[0], &id, 2);
 1599     }
 1600 
 1601     /*
 1602      * Digest the modified header.
 1603      */
 1604     header_r.base = (unsigned char *)header;
 1605     header_r.length = DNS_MESSAGE_HEADERLEN;
 1606     ret = dst_context_adddata(msg->tsigctx, &header_r);
 1607     if (ret != ISC_R_SUCCESS) {
 1608         goto cleanup_context;
 1609     }
 1610 
 1611     /*
 1612      * Digest all non-TSIG records.
 1613      */
 1614     isc_buffer_usedregion(source, &source_r);
 1615     r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
 1616     if (has_tsig) {
 1617         r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
 1618     } else {
 1619         r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
 1620     }
 1621     ret = dst_context_adddata(msg->tsigctx, &r);
 1622     if (ret != ISC_R_SUCCESS) {
 1623         goto cleanup_context;
 1624     }
 1625 
 1626     /*
 1627      * Digest the time signed and fudge.
 1628      */
 1629     if (has_tsig) {
 1630         isc_buffer_init(&databuf, data, sizeof(data));
 1631         isc_buffer_putuint48(&databuf, tsig.timesigned);
 1632         isc_buffer_putuint16(&databuf, tsig.fudge);
 1633         isc_buffer_usedregion(&databuf, &r);
 1634         ret = dst_context_adddata(msg->tsigctx, &r);
 1635         if (ret != ISC_R_SUCCESS) {
 1636             goto cleanup_context;
 1637         }
 1638 
 1639         sig_r.base = tsig.signature;
 1640         sig_r.length = tsig.siglen;
 1641         if (tsig.siglen == 0) {
 1642             if (tsig.error != dns_rcode_noerror) {
 1643                 msg->tsigstatus = tsig.error;
 1644                 if (tsig.error == dns_tsigerror_badtime) {
 1645                     ret = DNS_R_CLOCKSKEW;
 1646                 } else {
 1647                     ret = DNS_R_TSIGERRORSET;
 1648                 }
 1649             } else {
 1650                 tsig_log(msg->tsigkey, 2, "signature is empty");
 1651                 ret = DNS_R_TSIGVERIFYFAILURE;
 1652             }
 1653             goto cleanup_context;
 1654         }
 1655 
 1656         ret = dst_context_verify(msg->tsigctx, &sig_r);
 1657         if (ret == DST_R_VERIFYFAILURE) {
 1658             tsig_log(msg->tsigkey, 2,
 1659                  "signature failed to verify(2)");
 1660             ret = DNS_R_TSIGVERIFYFAILURE;
 1661             goto cleanup_context;
 1662         } else if (ret != ISC_R_SUCCESS) {
 1663             goto cleanup_context;
 1664         }
 1665         msg->verified_sig = 1;
 1666 
 1667         /*
 1668          * Here at this point, the MAC has been verified. Even
 1669          * if any of the following code returns a TSIG error,
 1670          * the reply will be signed and WILL always include the
 1671          * request MAC in the digest computation.
 1672          */
 1673 
 1674         /*
 1675          * Is the time ok?
 1676          */
 1677         isc_stdtime_get(&now);
 1678 
 1679         if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
 1680             msg->tsigstatus = dns_tsigerror_badtime;
 1681             tsig_log(msg->tsigkey, 2, "signature has expired");
 1682             ret = DNS_R_CLOCKSKEW;
 1683             goto cleanup_context;
 1684         } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge)
 1685         {
 1686             msg->tsigstatus = dns_tsigerror_badtime;
 1687             tsig_log(msg->tsigkey, 2, "signature is in the future");
 1688             ret = DNS_R_CLOCKSKEW;
 1689             goto cleanup_context;
 1690         }
 1691 
 1692         alg = dst_key_alg(key);
 1693         ret = dst_key_sigsize(key, &siglen);
 1694         if (ret != ISC_R_SUCCESS) {
 1695             goto cleanup_context;
 1696         }
 1697         if (dns__tsig_algvalid(alg)) {
 1698             uint16_t digestbits = dst_key_getbits(key);
 1699 
 1700             if (tsig.siglen > 0 && digestbits != 0 &&
 1701                 tsig.siglen < ((digestbits + 7) / 8)) {
 1702                 msg->tsigstatus = dns_tsigerror_badtrunc;
 1703                 tsig_log(msg->tsigkey, 2,
 1704                      "truncated signature length "
 1705                      "too small");
 1706                 ret = DNS_R_TSIGVERIFYFAILURE;
 1707                 goto cleanup_context;
 1708             }
 1709             if (tsig.siglen > 0 && digestbits == 0 &&
 1710                 tsig.siglen < siglen) {
 1711                 msg->tsigstatus = dns_tsigerror_badtrunc;
 1712                 tsig_log(msg->tsigkey, 2,
 1713                      "signature length too small");
 1714                 ret = DNS_R_TSIGVERIFYFAILURE;
 1715                 goto cleanup_context;
 1716             }
 1717         }
 1718 
 1719         if (tsig.error != dns_rcode_noerror) {
 1720             msg->tsigstatus = tsig.error;
 1721             if (tsig.error == dns_tsigerror_badtime) {
 1722                 ret = DNS_R_CLOCKSKEW;
 1723             } else {
 1724                 ret = DNS_R_TSIGERRORSET;
 1725             }
 1726             goto cleanup_context;
 1727         }
 1728     }
 1729 
 1730     msg->tsigstatus = dns_rcode_noerror;
 1731     ret = ISC_R_SUCCESS;
 1732 
 1733 cleanup_context:
 1734     /*
 1735      * Except in error conditions, don't destroy the DST context
 1736      * for unsigned messages; it is a running sum till the next
 1737      * TSIG signed message.
 1738      */
 1739     if ((ret != ISC_R_SUCCESS || has_tsig) && msg->tsigctx != NULL) {
 1740         dst_context_destroy(&msg->tsigctx);
 1741     }
 1742 
 1743 cleanup_querystruct:
 1744     dns_rdata_freestruct(&querytsig);
 1745 
 1746     return (ret);
 1747 }
 1748 
 1749 isc_result_t
 1750 dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name,
 1751          const dns_name_t *algorithm, dns_tsig_keyring_t *ring) {
 1752     dns_tsigkey_t *key;
 1753     isc_stdtime_t now;
 1754     isc_result_t result;
 1755 
 1756     REQUIRE(tsigkey != NULL);
 1757     REQUIRE(*tsigkey == NULL);
 1758     REQUIRE(name != NULL);
 1759     REQUIRE(ring != NULL);
 1760 
 1761     RWLOCK(&ring->lock, isc_rwlocktype_write);
 1762     cleanup_ring(ring);
 1763     RWUNLOCK(&ring->lock, isc_rwlocktype_write);
 1764 
 1765     isc_stdtime_get(&now);
 1766     RWLOCK(&ring->lock, isc_rwlocktype_read);
 1767     key = NULL;
 1768     result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key);
 1769     if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) {
 1770         RWUNLOCK(&ring->lock, isc_rwlocktype_read);
 1771         return (ISC_R_NOTFOUND);
 1772     }
 1773     if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
 1774         RWUNLOCK(&ring->lock, isc_rwlocktype_read);
 1775         return (ISC_R_NOTFOUND);
 1776     }
 1777     if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
 1778         /*
 1779          * The key has expired.
 1780          */
 1781         RWUNLOCK(&ring->lock, isc_rwlocktype_read);
 1782         RWLOCK(&ring->lock, isc_rwlocktype_write);
 1783         remove_fromring(key);
 1784         RWUNLOCK(&ring->lock, isc_rwlocktype_write);
 1785         return (ISC_R_NOTFOUND);
 1786     }
 1787 #if 0
 1788     /*
 1789      * MPAXXX We really should look at the inception time.
 1790      */
 1791     if (key->inception != key->expire &&
 1792         isc_serial_lt(key->inception, now)) {
 1793         RWUNLOCK(&ring->lock, isc_rwlocktype_read);
 1794         adjust_lru(key);
 1795         return (ISC_R_NOTFOUND);
 1796     }
 1797 #endif /* if 0 */
 1798     isc_refcount_increment(&key->refs);
 1799     RWUNLOCK(&ring->lock, isc_rwlocktype_read);
 1800     adjust_lru(key);
 1801     *tsigkey = key;
 1802     return (ISC_R_SUCCESS);
 1803 }
 1804 
 1805 static void
 1806 free_tsignode(void *node, void *_unused) {
 1807     dns_tsigkey_t *key;
 1808 
 1809     REQUIRE(node != NULL);
 1810 
 1811     UNUSED(_unused);
 1812 
 1813     key = node;
 1814     if (key->generated) {
 1815         if (ISC_LINK_LINKED(key, link)) {
 1816             ISC_LIST_UNLINK(key->ring->lru, key, link);
 1817         }
 1818     }
 1819     dns_tsigkey_detach(&key);
 1820 }
 1821 
 1822 isc_result_t
 1823 dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
 1824     isc_result_t result;
 1825     dns_tsig_keyring_t *ring;
 1826 
 1827     REQUIRE(mctx != NULL);
 1828     REQUIRE(ringp != NULL);
 1829     REQUIRE(*ringp == NULL);
 1830 
 1831     ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
 1832 
 1833     result = isc_rwlock_init(&ring->lock, 0, 0);
 1834     if (result != ISC_R_SUCCESS) {
 1835         isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
 1836         return (result);
 1837     }
 1838 
 1839     ring->keys = NULL;
 1840     result = dns_rbt_create(mctx, free_tsignode, NULL, &ring->keys);
 1841     if (result != ISC_R_SUCCESS) {
 1842         isc_rwlock_destroy(&ring->lock);
 1843         isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
 1844         return (result);
 1845     }
 1846 
 1847     ring->writecount = 0;
 1848     ring->mctx = NULL;
 1849     ring->generated = 0;
 1850     ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS;
 1851     ISC_LIST_INIT(ring->lru);
 1852     isc_mem_attach(mctx, &ring->mctx);
 1853     isc_refcount_init(&ring->references, 1);
 1854 
 1855     *ringp = ring;
 1856     return (ISC_R_SUCCESS);
 1857 }
 1858 
 1859 isc_result_t
 1860 dns_tsigkeyring_add(dns_tsig_keyring_t *ring, const dns_name_t *name,
 1861             dns_tsigkey_t *tkey) {
 1862     isc_result_t result;
 1863 
 1864     result = keyring_add(ring, name, tkey);
 1865     if (result == ISC_R_SUCCESS) {
 1866         isc_refcount_increment(&tkey->refs);
 1867     }
 1868 
 1869     return (result);
 1870 }
 1871 
 1872 void
 1873 dns_tsigkeyring_attach(dns_tsig_keyring_t *source,
 1874                dns_tsig_keyring_t **target) {
 1875     REQUIRE(source != NULL);
 1876     REQUIRE(target != NULL && *target == NULL);
 1877 
 1878     isc_refcount_increment(&source->references);
 1879 
 1880     *target = source;
 1881 }
 1882 
 1883 void
 1884 dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp) {
 1885     dns_tsig_keyring_t *ring;
 1886 
 1887     REQUIRE(ringp != NULL);
 1888     REQUIRE(*ringp != NULL);
 1889 
 1890     ring = *ringp;
 1891     *ringp = NULL;
 1892 
 1893     if (isc_refcount_decrement(&ring->references) == 1) {
 1894         destroyring(ring);
 1895     }
 1896 }
 1897 
 1898 void
 1899 dns_keyring_restore(dns_tsig_keyring_t *ring, FILE *fp) {
 1900     isc_stdtime_t now;
 1901     isc_result_t result;
 1902 
 1903     isc_stdtime_get(&now);
 1904     do {
 1905         result = restore_key(ring, now, fp);
 1906         if (result == ISC_R_NOMORE) {
 1907             return;
 1908         }
 1909         if (result == DNS_R_BADALG || result == DNS_R_EXPIRED) {
 1910             result = ISC_R_SUCCESS;
 1911         }
 1912     } while (result == ISC_R_SUCCESS);
 1913 }