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