Merge from vendor branch TCPDUMP:
[dragonfly.git] / contrib / bind-9.3 / lib / dns / tsig.c
1 /*
2  * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2002  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /*
19  * $Id: tsig.c,v 1.112.2.3.8.6 2005/03/17 03:58:31 marka Exp $
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24
25 #include <isc/buffer.h>
26 #include <isc/mem.h>
27 #include <isc/print.h>
28 #include <isc/refcount.h>
29 #include <isc/string.h>         /* Required for HP/UX (and others?) */
30 #include <isc/util.h>
31
32 #include <dns/keyvalues.h>
33 #include <dns/log.h>
34 #include <dns/message.h>
35 #include <dns/rbt.h>
36 #include <dns/rdata.h>
37 #include <dns/rdatalist.h>
38 #include <dns/rdataset.h>
39 #include <dns/rdatastruct.h>
40 #include <dns/result.h>
41 #include <dns/tsig.h>
42
43 #include <dst/result.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 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
49 #define algname_is_allocated(algname) \
50         ((algname) != dns_tsig_hmacmd5_name && \
51          (algname) != dns_tsig_gssapi_name && \
52          (algname) != dns_tsig_gssapims_name)
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 hmacmd5 = {
60         DNS_NAME_MAGIC,
61         hmacmd5_ndata, 26, 5,
62         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
63         hmacmd5_offsets, NULL,
64         {(void *)-1, (void *)-1},
65         {NULL, NULL}
66 };
67
68 dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
69
70 static unsigned char gsstsig_ndata[] = "\010gss-tsig";
71 static unsigned char gsstsig_offsets[] = { 0, 9 };
72
73 static dns_name_t gsstsig = {
74         DNS_NAME_MAGIC,
75         gsstsig_ndata, 10, 2,
76         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
77         gsstsig_offsets, NULL,
78         {(void *)-1, (void *)-1},
79         {NULL, NULL}
80 };
81
82 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig;
83
84 /* It's nice of Microsoft to conform to their own standard. */
85 static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com";
86 static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 };
87
88 static dns_name_t gsstsigms = {
89         DNS_NAME_MAGIC,
90         gsstsigms_ndata, 19, 4,
91         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
92         gsstsigms_offsets, NULL,
93         {(void *)-1, (void *)-1},
94         {NULL, NULL}
95 };
96
97 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapims_name = &gsstsigms;
98
99 static isc_result_t
100 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
101
102 static void
103 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
104      ISC_FORMAT_PRINTF(3, 4);
105
106 static void
107 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
108         va_list ap;
109         char message[4096];
110         char namestr[DNS_NAME_FORMATSIZE];
111
112         if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
113                 return;
114         if (key != NULL)
115                 dns_name_format(&key->name, namestr, sizeof(namestr));
116         else
117                 strcpy(namestr, "<null>");
118         va_start(ap, fmt);
119         vsnprintf(message, sizeof(message), fmt, ap);
120         va_end(ap);
121         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
122                       level, "tsig key '%s': %s", namestr, message);
123 }
124
125 isc_result_t
126 dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
127                           dst_key_t *dstkey, isc_boolean_t generated,
128                           dns_name_t *creator, isc_stdtime_t inception,
129                           isc_stdtime_t expire, isc_mem_t *mctx,
130                           dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
131 {
132         dns_tsigkey_t *tkey;
133         isc_result_t ret;
134         unsigned int refs = 0;
135
136         REQUIRE(key == NULL || *key == NULL);
137         REQUIRE(name != NULL);
138         REQUIRE(algorithm != NULL);
139         REQUIRE(mctx != NULL);
140
141         tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t));
142         if (tkey == NULL)
143                 return (ISC_R_NOMEMORY);
144
145         dns_name_init(&tkey->name, NULL);
146         ret = dns_name_dup(name, mctx, &tkey->name);
147         if (ret != ISC_R_SUCCESS)
148                 goto cleanup_key;
149         (void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
150
151         if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
152                 tkey->algorithm = DNS_TSIG_HMACMD5_NAME;
153                 if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) {
154                         ret = DNS_R_BADALG;
155                         goto cleanup_name;
156                 }
157         } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) {
158                 tkey->algorithm = DNS_TSIG_GSSAPI_NAME;
159                 if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
160                         ret = DNS_R_BADALG;
161                         goto cleanup_name;
162                 }
163         } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
164                 tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME;
165                 if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
166                         ret = DNS_R_BADALG;
167                         goto cleanup_name;
168                 }
169         } else {
170                 if (dstkey != NULL) {
171                         ret = DNS_R_BADALG;
172                         goto cleanup_name;
173                 }
174                 tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t));
175                 if (tkey->algorithm == NULL) {
176                         ret = ISC_R_NOMEMORY;
177                         goto cleanup_name;
178                 }
179                 dns_name_init(tkey->algorithm, NULL);
180                 ret = dns_name_dup(algorithm, mctx, tkey->algorithm);
181                 if (ret != ISC_R_SUCCESS)
182                         goto cleanup_algorithm;
183                 (void)dns_name_downcase(tkey->algorithm, tkey->algorithm,
184                                         NULL);
185         }
186
187         if (creator != NULL) {
188                 tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
189                 if (tkey->creator == NULL) {
190                         ret = ISC_R_NOMEMORY;
191                         goto cleanup_algorithm;
192                 }
193                 dns_name_init(tkey->creator, NULL);
194                 ret = dns_name_dup(creator, mctx, tkey->creator);
195                 if (ret != ISC_R_SUCCESS) {
196                         isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
197                         goto cleanup_algorithm;
198                 }
199         } else
200                 tkey->creator = NULL;
201
202         tkey->key = dstkey;
203         tkey->ring = ring;
204
205         if (ring != NULL) {
206                 RWLOCK(&ring->lock, isc_rwlocktype_write);
207                 ret = dns_rbt_addname(ring->keys, name, tkey);
208                 if (ret != ISC_R_SUCCESS) {
209                         RWUNLOCK(&ring->lock, isc_rwlocktype_write);
210                         goto cleanup_algorithm;
211                 }
212                 refs++;
213                 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
214         }
215
216         if (key != NULL)
217                 refs++;
218         isc_refcount_init(&tkey->refs, refs);
219         tkey->generated = generated;
220         tkey->inception = inception;
221         tkey->expire = expire;
222         tkey->mctx = mctx;
223
224         tkey->magic = TSIG_MAGIC;
225
226         if (dstkey != NULL && dst_key_size(dstkey) < 64) {
227                 char namestr[DNS_NAME_FORMATSIZE];
228                 dns_name_format(name, namestr, sizeof(namestr));
229                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
230                               DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
231                               "the key '%s' is too short to be secure",
232                               namestr);
233         }
234         if (key != NULL)
235                 *key = tkey;
236
237         return (ISC_R_SUCCESS);
238
239  cleanup_algorithm:
240         if (algname_is_allocated(tkey->algorithm)) {
241                 if (dns_name_dynamic(tkey->algorithm))
242                         dns_name_free(tkey->algorithm, mctx);
243                 isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t));
244         }
245  cleanup_name:
246         dns_name_free(&tkey->name, mctx);
247  cleanup_key:
248         isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));
249
250         return (ret);
251 }
252
253 isc_result_t
254 dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
255                    unsigned char *secret, int length, isc_boolean_t generated,
256                    dns_name_t *creator, isc_stdtime_t inception,
257                    isc_stdtime_t expire, isc_mem_t *mctx,
258                    dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
259 {
260         dst_key_t *dstkey = NULL;
261         isc_result_t result;
262
263         REQUIRE(length >= 0);
264         if (length > 0)
265                 REQUIRE(secret != NULL);
266
267         if (!dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) && length > 0)
268                 return (DNS_R_BADALG);
269
270         if (secret != NULL) {
271                 isc_buffer_t b;
272
273                 isc_buffer_init(&b, secret, length);
274                 isc_buffer_add(&b, length);
275                 result = dst_key_frombuffer(name, DST_ALG_HMACMD5,
276                                             DNS_KEYOWNER_ENTITY,
277                                             DNS_KEYPROTO_DNSSEC,
278                                             dns_rdataclass_in,
279                                             &b, mctx, &dstkey);
280                 if (result != ISC_R_SUCCESS)
281                         return (result);
282         }
283         result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
284                                            generated, creator,
285                                            inception, expire, mctx, ring, key);
286         if (result != ISC_R_SUCCESS && dstkey != NULL)
287                 dst_key_free(&dstkey);
288         return (result);
289 }
290
291 void
292 dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp) {
293         REQUIRE(VALID_TSIG_KEY(source));
294         REQUIRE(targetp != NULL && *targetp == NULL);
295
296         isc_refcount_increment(&source->refs, NULL);
297         *targetp = source;
298 }
299
300 static void
301 tsigkey_free(dns_tsigkey_t *key) {
302         REQUIRE(VALID_TSIG_KEY(key));
303
304         key->magic = 0;
305         dns_name_free(&key->name, key->mctx);
306         if (algname_is_allocated(key->algorithm)) {
307                 dns_name_free(key->algorithm, key->mctx);
308                 isc_mem_put(key->mctx, key->algorithm, sizeof(dns_name_t));
309         }
310         if (key->key != NULL)
311                 dst_key_free(&key->key);
312         if (key->creator != NULL) {
313                 dns_name_free(key->creator, key->mctx);
314                 isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
315         }
316         isc_refcount_destroy(&key->refs);
317         isc_mem_put(key->mctx, key, sizeof(dns_tsigkey_t));
318 }
319
320 void
321 dns_tsigkey_detach(dns_tsigkey_t **keyp) {
322         dns_tsigkey_t *key;
323         unsigned int refs;
324
325         REQUIRE(keyp != NULL);
326         REQUIRE(VALID_TSIG_KEY(*keyp));
327
328         key = *keyp;
329         isc_refcount_decrement(&key->refs, &refs);
330
331         if (refs == 0)
332                 tsigkey_free(key);
333
334         *keyp = NULL;
335 }
336
337 void
338 dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
339         REQUIRE(VALID_TSIG_KEY(key));
340         REQUIRE(key->ring != NULL);
341
342         RWLOCK(&key->ring->lock, isc_rwlocktype_write);
343         (void)dns_rbt_deletename(key->ring->keys, &key->name, ISC_FALSE);
344         RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
345 }
346
347 static void
348 buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
349         isc_uint16_t valhi;
350         isc_uint32_t vallo;
351
352         valhi = (isc_uint16_t)(val >> 32);
353         vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
354         isc_buffer_putuint16(b, valhi);
355         isc_buffer_putuint32(b, vallo);
356 }
357
358 isc_result_t
359 dns_tsig_sign(dns_message_t *msg) {
360         dns_tsigkey_t *key;
361         dns_rdata_any_tsig_t tsig, querytsig;
362         unsigned char data[128];
363         isc_buffer_t databuf, sigbuf;
364         isc_buffer_t *dynbuf;
365         dns_name_t *owner;
366         dns_rdata_t *rdata;
367         dns_rdatalist_t *datalist;
368         dns_rdataset_t *dataset;
369         isc_region_t r;
370         isc_stdtime_t now;
371         isc_mem_t *mctx;
372         dst_context_t *ctx = NULL;
373         isc_result_t ret;
374         unsigned char badtimedata[BADTIMELEN];
375         unsigned int sigsize = 0;
376
377         REQUIRE(msg != NULL);
378         REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));
379
380         /*
381          * If this is a response, there should be a query tsig.
382          */
383         if (is_response(msg) && msg->querytsig == NULL)
384                 return (DNS_R_EXPECTEDTSIG);
385
386         dynbuf = NULL;
387
388         mctx = msg->mctx;
389         key = dns_message_gettsigkey(msg);
390
391         tsig.mctx = mctx;
392         tsig.common.rdclass = dns_rdataclass_any;
393         tsig.common.rdtype = dns_rdatatype_tsig;
394         ISC_LINK_INIT(&tsig.common, link);
395         dns_name_init(&tsig.algorithm, NULL);
396         dns_name_clone(key->algorithm, &tsig.algorithm);
397
398         isc_stdtime_get(&now);
399         tsig.timesigned = now + msg->timeadjust;
400         tsig.fudge = DNS_TSIG_FUDGE;
401
402         tsig.originalid = msg->id;
403
404         isc_buffer_init(&databuf, data, sizeof(data));
405
406         if (is_response(msg))
407                 tsig.error = msg->querytsigstatus;
408         else
409                 tsig.error = dns_rcode_noerror;
410
411         if (tsig.error != dns_tsigerror_badtime) {
412                 tsig.otherlen = 0;
413                 tsig.other = NULL;
414         } else {
415                 isc_buffer_t otherbuf;
416
417                 tsig.otherlen = BADTIMELEN;
418                 tsig.other = badtimedata;
419                 isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
420                 buffer_putuint48(&otherbuf, tsig.timesigned);
421         }
422
423         if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
424                 unsigned char header[DNS_MESSAGE_HEADERLEN];
425                 isc_buffer_t headerbuf;
426
427                 ret = dst_context_create(key->key, mctx, &ctx);
428                 if (ret != ISC_R_SUCCESS)
429                         return (ret);
430
431                 /*
432                  * If this is a response, digest the query signature.
433                  */
434                 if (is_response(msg)) {
435                         dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
436
437                         ret = dns_rdataset_first(msg->querytsig);
438                         if (ret != ISC_R_SUCCESS)
439                                 goto cleanup_context;
440                         dns_rdataset_current(msg->querytsig, &querytsigrdata);
441                         ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
442                                                  NULL);
443                         if (ret != ISC_R_SUCCESS)
444                                 goto cleanup_context;
445                         isc_buffer_putuint16(&databuf, querytsig.siglen);
446                         if (isc_buffer_availablelength(&databuf) <
447                             querytsig.siglen)
448                         {
449                                 ret = ISC_R_NOSPACE;
450                                 goto cleanup_context;
451                         }
452                         isc_buffer_putmem(&databuf, querytsig.signature,
453                                           querytsig.siglen);
454                         isc_buffer_usedregion(&databuf, &r);
455                         ret = dst_context_adddata(ctx, &r);
456                         if (ret != ISC_R_SUCCESS)
457                                 goto cleanup_context;
458                 }
459
460                 /*
461                  * Digest the header.
462                  */
463                 isc_buffer_init(&headerbuf, header, sizeof(header));
464                 dns_message_renderheader(msg, &headerbuf);
465                 isc_buffer_usedregion(&headerbuf, &r);
466                 ret = dst_context_adddata(ctx, &r);
467                 if (ret != ISC_R_SUCCESS)
468                         goto cleanup_context;
469
470                 /*
471                  * Digest the remainder of the message.
472                  */
473                 isc_buffer_usedregion(msg->buffer, &r);
474                 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
475                 ret = dst_context_adddata(ctx, &r);
476                 if (ret != ISC_R_SUCCESS)
477                         goto cleanup_context;
478
479                 if (msg->tcp_continuation == 0) {
480                         /*
481                          * Digest the name, class, ttl, alg.
482                          */
483                         dns_name_toregion(&key->name, &r);
484                         ret = dst_context_adddata(ctx, &r);
485                         if (ret != ISC_R_SUCCESS)
486                                 goto cleanup_context;
487
488                         isc_buffer_clear(&databuf);
489                         isc_buffer_putuint16(&databuf, dns_rdataclass_any);
490                         isc_buffer_putuint32(&databuf, 0); /* ttl */
491                         isc_buffer_usedregion(&databuf, &r);
492                         ret = dst_context_adddata(ctx, &r);
493                         if (ret != ISC_R_SUCCESS)
494                                 goto cleanup_context;
495
496                         dns_name_toregion(&tsig.algorithm, &r);
497                         ret = dst_context_adddata(ctx, &r);
498                         if (ret != ISC_R_SUCCESS)
499                                 goto cleanup_context;
500
501                 }
502                 /* Digest the timesigned and fudge */
503                 isc_buffer_clear(&databuf);
504                 if (tsig.error == dns_tsigerror_badtime)
505                         tsig.timesigned = querytsig.timesigned;
506                 buffer_putuint48(&databuf, tsig.timesigned);
507                 isc_buffer_putuint16(&databuf, tsig.fudge);
508                 isc_buffer_usedregion(&databuf, &r);
509                 ret = dst_context_adddata(ctx, &r);
510                 if (ret != ISC_R_SUCCESS)
511                         goto cleanup_context;
512
513                 if (msg->tcp_continuation == 0) {
514                         /*
515                          * Digest the error and other data length.
516                          */
517                         isc_buffer_clear(&databuf);
518                         isc_buffer_putuint16(&databuf, tsig.error);
519                         isc_buffer_putuint16(&databuf, tsig.otherlen);
520
521                         isc_buffer_usedregion(&databuf, &r);
522                         ret = dst_context_adddata(ctx, &r);
523                         if (ret != ISC_R_SUCCESS)
524                                 goto cleanup_context;
525
526                         /*
527                          * Digest the error and other data.
528                          */
529                         if (tsig.otherlen > 0) {
530                                 r.length = tsig.otherlen;
531                                 r.base = tsig.other;
532                                 ret = dst_context_adddata(ctx, &r);
533                                 if (ret != ISC_R_SUCCESS)
534                                         goto cleanup_context;
535                         }
536                 }
537
538                 ret = dst_key_sigsize(key->key, &sigsize);
539                 if (ret != ISC_R_SUCCESS)
540                         goto cleanup_context;
541                 tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
542                 if (tsig.signature == NULL) {
543                         ret = ISC_R_NOMEMORY;
544                         goto cleanup_context;
545                 }
546
547                 isc_buffer_init(&sigbuf, tsig.signature, sigsize);
548                 ret = dst_context_sign(ctx, &sigbuf);
549                 if (ret != ISC_R_SUCCESS)
550                         goto cleanup_signature;
551                 dst_context_destroy(&ctx);
552                 tsig.siglen = isc_buffer_usedlength(&sigbuf);
553         } else {
554                 tsig.siglen = 0;
555                 tsig.signature = NULL;
556         }
557
558         rdata = NULL;
559         ret = dns_message_gettemprdata(msg, &rdata);
560         if (ret != ISC_R_SUCCESS)
561                 goto cleanup_signature;
562         ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
563         if (ret != ISC_R_SUCCESS)
564                 goto cleanup_signature;
565         ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
566                                    dns_rdatatype_tsig, &tsig, dynbuf);
567         if (ret != ISC_R_SUCCESS)
568                 goto cleanup_dynbuf;
569
570         dns_message_takebuffer(msg, &dynbuf);
571
572         if (tsig.signature != NULL) {
573                 isc_mem_put(mctx, tsig.signature, sigsize);
574                 tsig.signature = NULL;
575         }
576
577         owner = NULL;
578         ret = dns_message_gettempname(msg, &owner);
579         if (ret != ISC_R_SUCCESS)
580                 goto cleanup_dynbuf;
581         dns_name_init(owner, NULL);
582         ret = dns_name_dup(&key->name, msg->mctx, owner);
583         if (ret != ISC_R_SUCCESS)
584                 goto cleanup_owner;
585
586         datalist = NULL;
587         ret = dns_message_gettemprdatalist(msg, &datalist);
588         if (ret != ISC_R_SUCCESS)
589                 goto cleanup_owner;
590         datalist->rdclass = dns_rdataclass_any;
591         datalist->type = dns_rdatatype_tsig;
592         datalist->covers = 0;
593         datalist->ttl = 0;
594         ISC_LIST_INIT(datalist->rdata);
595         ISC_LIST_APPEND(datalist->rdata, rdata, link);
596         dataset = NULL;
597         ret = dns_message_gettemprdataset(msg, &dataset);
598         if (ret != ISC_R_SUCCESS)
599                 goto cleanup_owner;
600         dns_rdataset_init(dataset);
601         RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
602                       == ISC_R_SUCCESS);
603         msg->tsig = dataset;
604         msg->tsigname = owner;
605
606         return (ISC_R_SUCCESS);
607
608 cleanup_owner:
609         if (owner != NULL)
610                 dns_message_puttempname(msg, &owner);
611 cleanup_dynbuf:
612         if (dynbuf != NULL)
613                 isc_buffer_free(&dynbuf);
614 cleanup_signature:
615         if (tsig.signature != NULL)
616                 isc_mem_put(mctx, tsig.signature, sigsize);
617 cleanup_context:
618         if (ctx != NULL)
619                 dst_context_destroy(&ctx);
620         return (ret);
621 }
622
623 isc_result_t
624 dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
625                 dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2)
626 {
627         dns_rdata_any_tsig_t tsig, querytsig;
628         isc_region_t r, source_r, header_r, sig_r;
629         isc_buffer_t databuf;
630         unsigned char data[32];
631         dns_name_t *keyname;
632         dns_rdata_t rdata = DNS_RDATA_INIT;
633         isc_stdtime_t now;
634         isc_result_t ret;
635         dns_tsigkey_t *tsigkey;
636         dst_key_t *key = NULL;
637         unsigned char header[DNS_MESSAGE_HEADERLEN];
638         dst_context_t *ctx = NULL;
639         isc_mem_t *mctx;
640         isc_uint16_t addcount, id;
641
642         REQUIRE(source != NULL);
643         REQUIRE(DNS_MESSAGE_VALID(msg));
644         tsigkey = dns_message_gettsigkey(msg);
645         REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
646
647         msg->verify_attempted = 1;
648
649         if (msg->tcp_continuation)
650                 return (tsig_verify_tcp(source, msg));
651
652         /*
653          * There should be a TSIG record...
654          */
655         if (msg->tsig == NULL)
656                 return (DNS_R_EXPECTEDTSIG);
657
658         /*
659          * If this is a response and there's no key or query TSIG, there
660          * shouldn't be one on the response.
661          */
662         if (is_response(msg) &&
663             (tsigkey == NULL || msg->querytsig == NULL))
664                 return (DNS_R_UNEXPECTEDTSIG);
665
666         mctx = msg->mctx;
667
668         /*
669          * If we're here, we know the message is well formed and contains a
670          * TSIG record.
671          */
672
673         keyname = msg->tsigname;
674         ret = dns_rdataset_first(msg->tsig);
675         if (ret != ISC_R_SUCCESS)
676                 return (ret);
677         dns_rdataset_current(msg->tsig, &rdata);
678         ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
679         if (ret != ISC_R_SUCCESS)
680                 return (ret);
681         dns_rdata_reset(&rdata);
682         if (is_response(msg)) {
683                 ret = dns_rdataset_first(msg->querytsig);
684                 if (ret != ISC_R_SUCCESS)
685                         return (ret);
686                 dns_rdataset_current(msg->querytsig, &rdata);
687                 ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
688                 if (ret != ISC_R_SUCCESS)
689                         return (ret);
690         }
691
692         /*
693          * Do the key name and algorithm match that of the query?
694          */
695         if (is_response(msg) &&
696             (!dns_name_equal(keyname, &tsigkey->name) ||
697              !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
698         {
699                 msg->tsigstatus = dns_tsigerror_badkey;
700                 tsig_log(msg->tsigkey, 2,
701                          "key name and algorithm do not match");
702                 return (DNS_R_TSIGVERIFYFAILURE);
703         }
704
705         /*
706          * Get the current time.
707          */
708         isc_stdtime_get(&now);
709
710         /*
711          * Find dns_tsigkey_t based on keyname.
712          */
713         if (tsigkey == NULL) {
714                 ret = ISC_R_NOTFOUND;
715                 if (ring1 != NULL)
716                         ret = dns_tsigkey_find(&tsigkey, keyname,
717                                                &tsig.algorithm, ring1);
718                 if (ret == ISC_R_NOTFOUND && ring2 != NULL)
719                         ret = dns_tsigkey_find(&tsigkey, keyname,
720                                                &tsig.algorithm, ring2);
721                 if (ret != ISC_R_SUCCESS) {
722                         msg->tsigstatus = dns_tsigerror_badkey;
723                         ret = dns_tsigkey_create(keyname, &tsig.algorithm,
724                                                  NULL, 0, ISC_FALSE, NULL,
725                                                  now, now,
726                                                  mctx, NULL, &msg->tsigkey);
727                         if (ret != ISC_R_SUCCESS)
728                                 return (ret);
729                         tsig_log(msg->tsigkey, 2, "unknown key");
730                         return (DNS_R_TSIGVERIFYFAILURE);
731                 }
732                 msg->tsigkey = tsigkey;
733         }
734
735         key = tsigkey->key;
736
737         /*
738          * Is the time ok?
739          */
740         if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
741                 msg->tsigstatus = dns_tsigerror_badtime;
742                 tsig_log(msg->tsigkey, 2, "signature has expired");
743                 return (DNS_R_CLOCKSKEW);
744         } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
745                 msg->tsigstatus = dns_tsigerror_badtime;
746                 tsig_log(msg->tsigkey, 2, "signature is in the future");
747                 return (DNS_R_CLOCKSKEW);
748         }
749
750         if (tsig.siglen > 0) {
751                 sig_r.base = tsig.signature;
752                 sig_r.length = tsig.siglen;
753
754                 ret = dst_context_create(key, mctx, &ctx);
755                 if (ret != ISC_R_SUCCESS)
756                         return (ret);
757
758                 if (is_response(msg)) {
759                         isc_buffer_init(&databuf, data, sizeof(data));
760                         isc_buffer_putuint16(&databuf, querytsig.siglen);
761                         isc_buffer_usedregion(&databuf, &r);
762                         ret = dst_context_adddata(ctx, &r);
763                         if (ret != ISC_R_SUCCESS)
764                                 goto cleanup_context;
765                         if (querytsig.siglen > 0) {
766                                 r.length = querytsig.siglen;
767                                 r.base = querytsig.signature;
768                                 ret = dst_context_adddata(ctx, &r);
769                                 if (ret != ISC_R_SUCCESS)
770                                         goto cleanup_context;
771                         }
772                 }
773
774                 /*
775                  * Extract the header.
776                  */
777                 isc_buffer_usedregion(source, &r);
778                 memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
779                 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
780
781                 /*
782                  * Decrement the additional field counter.
783                  */
784                 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
785                 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
786                 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
787
788                 /*
789                  * Put in the original id.
790                  */
791                 id = htons(tsig.originalid);
792                 memcpy(&header[0], &id, 2);
793
794                 /*
795                  * Digest the modified header.
796                  */
797                 header_r.base = (unsigned char *) header;
798                 header_r.length = DNS_MESSAGE_HEADERLEN;
799                 ret = dst_context_adddata(ctx, &header_r);
800                 if (ret != ISC_R_SUCCESS)
801                         goto cleanup_context;
802
803                 /*
804                  * Digest all non-TSIG records.
805                  */
806                 isc_buffer_usedregion(source, &source_r);
807                 r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
808                 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
809                 ret = dst_context_adddata(ctx, &r);
810                 if (ret != ISC_R_SUCCESS)
811                         goto cleanup_context;
812
813                 /*
814                  * Digest the key name.
815                  */
816                 dns_name_toregion(&tsigkey->name, &r);
817                 ret = dst_context_adddata(ctx, &r);
818                 if (ret != ISC_R_SUCCESS)
819                         goto cleanup_context;
820
821                 isc_buffer_init(&databuf, data, sizeof(data));
822                 isc_buffer_putuint16(&databuf, tsig.common.rdclass);
823                 isc_buffer_putuint32(&databuf, msg->tsig->ttl);
824                 isc_buffer_usedregion(&databuf, &r);
825                 ret = dst_context_adddata(ctx, &r);
826                 if (ret != ISC_R_SUCCESS)
827                         goto cleanup_context;
828
829                 /*
830                  * Digest the key algorithm.
831                  */
832                 dns_name_toregion(tsigkey->algorithm, &r);
833                 ret = dst_context_adddata(ctx, &r);
834                 if (ret != ISC_R_SUCCESS)
835                         goto cleanup_context;
836
837                 isc_buffer_clear(&databuf);
838                 buffer_putuint48(&databuf, tsig.timesigned);
839                 isc_buffer_putuint16(&databuf, tsig.fudge);
840                 isc_buffer_putuint16(&databuf, tsig.error);
841                 isc_buffer_putuint16(&databuf, tsig.otherlen);
842                 isc_buffer_usedregion(&databuf, &r);
843                 ret = dst_context_adddata(ctx, &r);
844                 if (ret != ISC_R_SUCCESS)
845                         goto cleanup_context;
846
847                 if (tsig.otherlen > 0) {
848                         r.base = tsig.other;
849                         r.length = tsig.otherlen;
850                         ret = dst_context_adddata(ctx, &r);
851                         if (ret != ISC_R_SUCCESS)
852                                 goto cleanup_context;
853                 }
854
855                 ret = dst_context_verify(ctx, &sig_r);
856                 if (ret == DST_R_VERIFYFAILURE) {
857                         msg->tsigstatus = dns_tsigerror_badsig;
858                         ret = DNS_R_TSIGVERIFYFAILURE;
859                         tsig_log(msg->tsigkey, 2,
860                                  "signature failed to verify");
861                         goto cleanup_context;
862                 } else if (ret != ISC_R_SUCCESS)
863                         goto cleanup_context;
864
865                 dst_context_destroy(&ctx);
866         } else if (tsig.error != dns_tsigerror_badsig &&
867                    tsig.error != dns_tsigerror_badkey)
868         {
869                 msg->tsigstatus = dns_tsigerror_badsig;
870                 tsig_log(msg->tsigkey, 2, "signature was empty");
871                 return (DNS_R_TSIGVERIFYFAILURE);
872         }
873
874         msg->tsigstatus = dns_rcode_noerror;
875
876         if (tsig.error != dns_rcode_noerror) {
877                 if (tsig.error == dns_tsigerror_badtime)
878                         return (DNS_R_CLOCKSKEW);
879                 else
880                         return (DNS_R_TSIGERRORSET);
881         }
882
883         msg->verified_sig = 1;
884
885         return (ISC_R_SUCCESS);
886
887 cleanup_context:
888         if (ctx != NULL)
889                 dst_context_destroy(&ctx);
890
891         return (ret);
892 }
893
894 static isc_result_t
895 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
896         dns_rdata_any_tsig_t tsig, querytsig;
897         isc_region_t r, source_r, header_r, sig_r;
898         isc_buffer_t databuf;
899         unsigned char data[32];
900         dns_name_t *keyname;
901         dns_rdata_t rdata = DNS_RDATA_INIT;
902         isc_stdtime_t now;
903         isc_result_t ret;
904         dns_tsigkey_t *tsigkey;
905         dst_key_t *key = NULL;
906         unsigned char header[DNS_MESSAGE_HEADERLEN];
907         isc_uint16_t addcount, id;
908         isc_boolean_t has_tsig = ISC_FALSE;
909         isc_mem_t *mctx;
910
911         REQUIRE(source != NULL);
912         REQUIRE(msg != NULL);
913         REQUIRE(dns_message_gettsigkey(msg) != NULL);
914         REQUIRE(msg->tcp_continuation == 1);
915         REQUIRE(msg->querytsig != NULL);
916
917         if (!is_response(msg))
918                 return (DNS_R_EXPECTEDRESPONSE);
919
920         mctx = msg->mctx;
921
922         tsigkey = dns_message_gettsigkey(msg);
923
924         /*
925          * Extract and parse the previous TSIG
926          */
927         ret = dns_rdataset_first(msg->querytsig);
928         if (ret != ISC_R_SUCCESS)
929                 return (ret);
930         dns_rdataset_current(msg->querytsig, &rdata);
931         ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
932         if (ret != ISC_R_SUCCESS)
933                 return (ret);
934         dns_rdata_reset(&rdata);
935
936         /*
937          * If there is a TSIG in this message, do some checks.
938          */
939         if (msg->tsig != NULL) {
940                 has_tsig = ISC_TRUE;
941
942                 keyname = msg->tsigname;
943                 ret = dns_rdataset_first(msg->tsig);
944                 if (ret != ISC_R_SUCCESS)
945                         goto cleanup_querystruct;
946                 dns_rdataset_current(msg->tsig, &rdata);
947                 ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
948                 if (ret != ISC_R_SUCCESS)
949                         goto cleanup_querystruct;
950
951                 /*
952                  * Do the key name and algorithm match that of the query?
953                  */
954                 if (!dns_name_equal(keyname, &tsigkey->name) ||
955                     !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
956                 {
957                         msg->tsigstatus = dns_tsigerror_badkey;
958                         ret = DNS_R_TSIGVERIFYFAILURE;
959                         tsig_log(msg->tsigkey, 2,
960                                  "key name and algorithm do not match");
961                         goto cleanup_querystruct;
962                 }
963
964                 /*
965                  * Is the time ok?
966                  */
967                 isc_stdtime_get(&now);
968
969                 if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
970                         msg->tsigstatus = dns_tsigerror_badtime;
971                         tsig_log(msg->tsigkey, 2, "signature has expired");
972                         ret = DNS_R_CLOCKSKEW;
973                         goto cleanup_querystruct;
974                 } else if (now + msg->timeadjust <
975                            tsig.timesigned - tsig.fudge)
976                 {
977                         msg->tsigstatus = dns_tsigerror_badtime;
978                         tsig_log(msg->tsigkey, 2,
979                                  "signature is in the future");
980                         ret = DNS_R_CLOCKSKEW;
981                         goto cleanup_querystruct;
982                 }
983         }
984
985         key = tsigkey->key;
986
987         if (msg->tsigctx == NULL) {
988                 ret = dst_context_create(key, mctx, &msg->tsigctx);
989                 if (ret != ISC_R_SUCCESS)
990                         goto cleanup_querystruct;
991
992                 /*
993                  * Digest the length of the query signature
994                  */
995                 isc_buffer_init(&databuf, data, sizeof(data));
996                 isc_buffer_putuint16(&databuf, querytsig.siglen);
997                 isc_buffer_usedregion(&databuf, &r);
998                 ret = dst_context_adddata(msg->tsigctx, &r);
999                 if (ret != ISC_R_SUCCESS)
1000                         goto cleanup_context;
1001
1002                 /*
1003                  * Digest the data of the query signature
1004                  */
1005                 if (querytsig.siglen > 0) {
1006                         r.length = querytsig.siglen;
1007                         r.base = querytsig.signature;
1008                         ret = dst_context_adddata(msg->tsigctx, &r);
1009                         if (ret != ISC_R_SUCCESS)
1010                                 goto cleanup_context;
1011                 }
1012         }
1013
1014         /*
1015          * Extract the header.
1016          */
1017         isc_buffer_usedregion(source, &r);
1018         memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
1019         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1020
1021         /*
1022          * Decrement the additional field counter if necessary.
1023          */
1024         if (has_tsig) {
1025                 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1026                 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1027                 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1028         }
1029
1030         /*
1031          * Put in the original id.
1032          */
1033         /* XXX Can TCP transfers be forwarded?  How would that work? */
1034         if (has_tsig) {
1035                 id = htons(tsig.originalid);
1036                 memcpy(&header[0], &id, 2);
1037         }
1038
1039         /*
1040          * Digest the modified header.
1041          */
1042         header_r.base = (unsigned char *) header;
1043         header_r.length = DNS_MESSAGE_HEADERLEN;
1044         ret = dst_context_adddata(msg->tsigctx, &header_r);
1045         if (ret != ISC_R_SUCCESS)
1046                 goto cleanup_context;
1047
1048         /*
1049          * Digest all non-TSIG records.
1050          */
1051         isc_buffer_usedregion(source, &source_r);
1052         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1053         if (has_tsig)
1054                 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1055         else
1056                 r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
1057         ret = dst_context_adddata(msg->tsigctx, &r);
1058         if (ret != ISC_R_SUCCESS)
1059                 goto cleanup_context;
1060
1061         /*
1062          * Digest the time signed and fudge.
1063          */
1064         if (has_tsig) {
1065                 isc_buffer_init(&databuf, data, sizeof(data));
1066                 buffer_putuint48(&databuf, tsig.timesigned);
1067                 isc_buffer_putuint16(&databuf, tsig.fudge);
1068                 isc_buffer_usedregion(&databuf, &r);
1069                 ret = dst_context_adddata(msg->tsigctx, &r);
1070                 if (ret != ISC_R_SUCCESS)
1071                         goto cleanup_context;
1072
1073                 sig_r.base = tsig.signature;
1074                 sig_r.length = tsig.siglen;
1075                 if (tsig.siglen == 0) {
1076                         if (tsig.error != dns_rcode_noerror) {
1077                                 if (tsig.error == dns_tsigerror_badtime)
1078                                         ret = DNS_R_CLOCKSKEW;
1079                                 else
1080                                         ret = DNS_R_TSIGERRORSET;
1081                         } else {
1082                                 tsig_log(msg->tsigkey, 2,
1083                                          "signature is empty");
1084                                 ret = DNS_R_TSIGVERIFYFAILURE;
1085                         }
1086                         goto cleanup_context;
1087                 }
1088
1089                 ret = dst_context_verify(msg->tsigctx, &sig_r);
1090                 if (ret == DST_R_VERIFYFAILURE) {
1091                         msg->tsigstatus = dns_tsigerror_badsig;
1092                         tsig_log(msg->tsigkey, 2,
1093                                  "signature failed to verify");
1094                         ret = DNS_R_TSIGVERIFYFAILURE;
1095                         goto cleanup_context;
1096                 }
1097                 else if (ret != ISC_R_SUCCESS)
1098                         goto cleanup_context;
1099
1100                 dst_context_destroy(&msg->tsigctx);
1101         }
1102
1103         msg->tsigstatus = dns_rcode_noerror;
1104         return (ISC_R_SUCCESS);
1105
1106  cleanup_context:
1107         dst_context_destroy(&msg->tsigctx);
1108
1109  cleanup_querystruct:
1110         dns_rdata_freestruct(&querytsig);
1111
1112         return (ret);
1113
1114 }
1115
1116 isc_result_t
1117 dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
1118                  dns_name_t *algorithm, dns_tsig_keyring_t *ring)
1119 {
1120         dns_tsigkey_t *key;
1121         isc_stdtime_t now;
1122         isc_result_t result;
1123
1124         REQUIRE(tsigkey != NULL);
1125         REQUIRE(*tsigkey == NULL);
1126         REQUIRE(name != NULL);
1127         REQUIRE(ring != NULL);
1128
1129         isc_stdtime_get(&now);
1130         RWLOCK(&ring->lock, isc_rwlocktype_read);
1131         key = NULL;
1132         result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key);
1133         if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) {
1134                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1135                 return (ISC_R_NOTFOUND);
1136         }
1137         if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
1138                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1139                 return (ISC_R_NOTFOUND);
1140         }
1141         if (key->inception != key->expire && key->expire < now) {
1142                 /*
1143                  * The key has expired.
1144                  */
1145                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1146                 RWLOCK(&ring->lock, isc_rwlocktype_write);
1147                 (void) dns_rbt_deletename(ring->keys, name, ISC_FALSE);
1148                 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1149                 return (ISC_R_NOTFOUND);
1150         }
1151
1152         isc_refcount_increment(&key->refs, NULL);
1153         RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1154         *tsigkey = key;
1155         return (ISC_R_SUCCESS);
1156 }
1157
1158 static void
1159 free_tsignode(void *node, void *_unused) {
1160         dns_tsigkey_t *key;
1161
1162         UNUSED(_unused);
1163
1164         REQUIRE(node != NULL);
1165
1166         key = node;
1167         dns_tsigkey_detach(&key);
1168 }
1169
1170 isc_result_t
1171 dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
1172         isc_result_t result;
1173         dns_tsig_keyring_t *ring;
1174
1175         REQUIRE(mctx != NULL);
1176         REQUIRE(ringp != NULL);
1177         REQUIRE(*ringp == NULL);
1178
1179         ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
1180         if (ring == NULL)
1181                 return (ISC_R_NOMEMORY);
1182
1183         result = isc_rwlock_init(&ring->lock, 0, 0);
1184         if (result != ISC_R_SUCCESS) {
1185                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1186                                  "isc_rwlock_init() failed: %s",
1187                                  isc_result_totext(result));
1188                 return (ISC_R_UNEXPECTED);
1189         }
1190
1191         ring->keys = NULL;
1192         result = dns_rbt_create(mctx, free_tsignode, NULL, &ring->keys);
1193         if (result != ISC_R_SUCCESS) {
1194                 isc_rwlock_destroy(&ring->lock);
1195                 isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1196                 return (result);
1197         }
1198
1199         ring->mctx = mctx;
1200
1201         *ringp = ring;
1202         return (ISC_R_SUCCESS);
1203 }
1204
1205 void
1206 dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) {
1207         dns_tsig_keyring_t *ring;
1208
1209         REQUIRE(ringp != NULL);
1210         REQUIRE(*ringp != NULL);
1211
1212         ring = *ringp;
1213         *ringp = NULL;
1214
1215         dns_rbt_destroy(&ring->keys);
1216         isc_rwlock_destroy(&ring->lock);
1217         isc_mem_put(ring->mctx, ring, sizeof(dns_tsig_keyring_t));
1218 }