Home | History | Annotate | Line # | Download | only in dns
dnssec.c revision 1.5
      1 /*	$NetBSD: dnssec.c,v 1.5 2019/10/17 16:47:00 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 /*! \file */
     15 
     16 #include <config.h>
     17 
     18 #include <inttypes.h>
     19 #include <stdbool.h>
     20 #include <stdlib.h>
     21 
     22 #include <isc/buffer.h>
     23 #include <isc/dir.h>
     24 #include <isc/mem.h>
     25 #include <isc/print.h>
     26 #include <isc/serial.h>
     27 #include <isc/string.h>
     28 #include <isc/util.h>
     29 
     30 #include <pk11/site.h>
     31 
     32 #include <dns/db.h>
     33 #include <dns/diff.h>
     34 #include <dns/dnssec.h>
     35 #include <dns/fixedname.h>
     36 #include <dns/keyvalues.h>
     37 #include <dns/log.h>
     38 #include <dns/message.h>
     39 #include <dns/rdata.h>
     40 #include <dns/rdatalist.h>
     41 #include <dns/rdataset.h>
     42 #include <dns/rdatastruct.h>
     43 #include <dns/result.h>
     44 #include <dns/stats.h>
     45 #include <dns/tsig.h>		/* for DNS_TSIG_FUDGE */
     46 
     47 #include <dst/result.h>
     48 
     49 LIBDNS_EXTERNAL_DATA isc_stats_t *dns_dnssec_stats;
     50 
     51 #define is_response(msg) ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
     52 
     53 #define RETERR(x) do { \
     54 	result = (x); \
     55 	if (result != ISC_R_SUCCESS) \
     56 		goto failure; \
     57 	} while (/*CONSTCOND*/0)
     58 
     59 
     60 #define TYPE_SIGN 0
     61 #define TYPE_VERIFY 1
     62 
     63 static isc_result_t
     64 digest_callback(void *arg, isc_region_t *data);
     65 
     66 static int
     67 rdata_compare_wrapper(const void *rdata1, const void *rdata2);
     68 
     69 static isc_result_t
     70 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
     71 			dns_rdata_t **rdata, int *nrdata);
     72 
     73 static isc_result_t
     74 digest_callback(void *arg, isc_region_t *data) {
     75 	dst_context_t *ctx = arg;
     76 
     77 	return (dst_context_adddata(ctx, data));
     78 }
     79 
     80 static inline void
     81 inc_stat(isc_statscounter_t counter) {
     82 	if (dns_dnssec_stats != NULL)
     83 		isc_stats_increment(dns_dnssec_stats, counter);
     84 }
     85 
     86 /*
     87  * Make qsort happy.
     88  */
     89 static int
     90 rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
     91 	return (dns_rdata_compare((const dns_rdata_t *)rdata1,
     92 				  (const dns_rdata_t *)rdata2));
     93 }
     94 
     95 /*
     96  * Sort the rdataset into an array.
     97  */
     98 static isc_result_t
     99 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
    100 			dns_rdata_t **rdata, int *nrdata)
    101 {
    102 	isc_result_t ret;
    103 	int i = 0, n;
    104 	dns_rdata_t *data;
    105 	dns_rdataset_t rdataset;
    106 
    107 	n = dns_rdataset_count(set);
    108 
    109 	data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
    110 	if (data == NULL)
    111 		return (ISC_R_NOMEMORY);
    112 
    113 	dns_rdataset_init(&rdataset);
    114 	dns_rdataset_clone(set, &rdataset);
    115 	ret = dns_rdataset_first(&rdataset);
    116 	if (ret != ISC_R_SUCCESS) {
    117 		dns_rdataset_disassociate(&rdataset);
    118 		isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
    119 		return (ret);
    120 	}
    121 
    122 	/*
    123 	 * Put them in the array.
    124 	 */
    125 	do {
    126 		dns_rdata_init(&data[i]);
    127 		dns_rdataset_current(&rdataset, &data[i++]);
    128 	} while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
    129 
    130 	/*
    131 	 * Sort the array.
    132 	 */
    133 	qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
    134 	*rdata = data;
    135 	*nrdata = n;
    136 	dns_rdataset_disassociate(&rdataset);
    137 	return (ISC_R_SUCCESS);
    138 }
    139 
    140 isc_result_t
    141 dns_dnssec_keyfromrdata(const dns_name_t *name, const dns_rdata_t *rdata,
    142 			isc_mem_t *mctx, dst_key_t **key)
    143 {
    144 	isc_buffer_t b;
    145 	isc_region_t r;
    146 
    147 	INSIST(name != NULL);
    148 	INSIST(rdata != NULL);
    149 	INSIST(mctx != NULL);
    150 	INSIST(key != NULL);
    151 	INSIST(*key == NULL);
    152 	REQUIRE(rdata->type == dns_rdatatype_key ||
    153 		rdata->type == dns_rdatatype_dnskey);
    154 
    155 	dns_rdata_toregion(rdata, &r);
    156 	isc_buffer_init(&b, r.base, r.length);
    157 	isc_buffer_add(&b, r.length);
    158 	return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
    159 }
    160 
    161 static isc_result_t
    162 digest_sig(dst_context_t *ctx, bool downcase, dns_rdata_t *sigrdata,
    163 	   dns_rdata_rrsig_t *rrsig)
    164 {
    165 	isc_region_t r;
    166 	isc_result_t ret;
    167 	dns_fixedname_t fname;
    168 
    169 	dns_rdata_toregion(sigrdata, &r);
    170 	INSIST(r.length >= 19);
    171 
    172 	r.length = 18;
    173 	ret = dst_context_adddata(ctx, &r);
    174 	if (ret != ISC_R_SUCCESS)
    175 		return (ret);
    176 	if (downcase) {
    177 		dns_fixedname_init(&fname);
    178 
    179 		RUNTIME_CHECK(dns_name_downcase(&rrsig->signer,
    180 						dns_fixedname_name(&fname),
    181 						NULL) == ISC_R_SUCCESS);
    182 		dns_name_toregion(dns_fixedname_name(&fname), &r);
    183 	} else
    184 		dns_name_toregion(&rrsig->signer, &r);
    185 
    186 	return (dst_context_adddata(ctx, &r));
    187 }
    188 
    189 isc_result_t
    190 dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
    191 		isc_stdtime_t *inception, isc_stdtime_t *expire,
    192 		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
    193 {
    194 	dns_rdata_rrsig_t sig;
    195 	dns_rdata_t tmpsigrdata;
    196 	dns_rdata_t *rdatas;
    197 	int nrdatas, i;
    198 	isc_buffer_t sigbuf, envbuf;
    199 	isc_region_t r;
    200 	dst_context_t *ctx = NULL;
    201 	isc_result_t ret;
    202 	isc_buffer_t *databuf = NULL;
    203 	char data[256 + 8];
    204 	uint32_t flags;
    205 	unsigned int sigsize;
    206 	dns_fixedname_t fnewname;
    207 	dns_fixedname_t fsigner;
    208 
    209 	REQUIRE(name != NULL);
    210 	REQUIRE(dns_name_countlabels(name) <= 255);
    211 	REQUIRE(set != NULL);
    212 	REQUIRE(key != NULL);
    213 	REQUIRE(inception != NULL);
    214 	REQUIRE(expire != NULL);
    215 	REQUIRE(mctx != NULL);
    216 	REQUIRE(sigrdata != NULL);
    217 
    218 	if (*inception >= *expire)
    219 		return (DNS_R_INVALIDTIME);
    220 
    221 	/*
    222 	 * Is the key allowed to sign data?
    223 	 */
    224 	flags = dst_key_flags(key);
    225 	if ((flags & DNS_KEYTYPE_NOAUTH) != 0) {
    226 		return (DNS_R_KEYUNAUTHORIZED);
    227 	}
    228 	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
    229 		return (DNS_R_KEYUNAUTHORIZED);
    230 	}
    231 
    232 	sig.mctx = mctx;
    233 	sig.common.rdclass = set->rdclass;
    234 	sig.common.rdtype = dns_rdatatype_rrsig;
    235 	ISC_LINK_INIT(&sig.common, link);
    236 
    237 	/*
    238 	 * Downcase signer.
    239 	 */
    240 	dns_name_init(&sig.signer, NULL);
    241 	dns_fixedname_init(&fsigner);
    242 	RUNTIME_CHECK(dns_name_downcase(dst_key_name(key),
    243 		      dns_fixedname_name(&fsigner), NULL) == ISC_R_SUCCESS);
    244 	dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer);
    245 
    246 	sig.covered = set->type;
    247 	sig.algorithm = dst_key_alg(key);
    248 	sig.labels = dns_name_countlabels(name) - 1;
    249 	if (dns_name_iswildcard(name))
    250 		sig.labels--;
    251 	sig.originalttl = set->ttl;
    252 	sig.timesigned = *inception;
    253 	sig.timeexpire = *expire;
    254 	sig.keyid = dst_key_id(key);
    255 	ret = dst_key_sigsize(key, &sigsize);
    256 	if (ret != ISC_R_SUCCESS)
    257 		return (ret);
    258 	sig.siglen = sigsize;
    259 	/*
    260 	 * The actual contents of sig.signature are not important yet, since
    261 	 * they're not used in digest_sig().
    262 	 */
    263 	sig.signature = isc_mem_get(mctx, sig.siglen);
    264 	if (sig.signature == NULL)
    265 		return (ISC_R_NOMEMORY);
    266 
    267 	ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
    268 	if (ret != ISC_R_SUCCESS)
    269 		goto cleanup_signature;
    270 
    271 	dns_rdata_init(&tmpsigrdata);
    272 	ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
    273 				   sig.common.rdtype, &sig, databuf);
    274 	if (ret != ISC_R_SUCCESS)
    275 		goto cleanup_databuf;
    276 
    277 	ret = dst_context_create(key, mctx,
    278 				 DNS_LOGCATEGORY_DNSSEC, true, 0, &ctx);
    279 	if (ret != ISC_R_SUCCESS)
    280 		goto cleanup_databuf;
    281 
    282 	/*
    283 	 * Digest the SIG rdata.
    284 	 */
    285 	ret = digest_sig(ctx, false, &tmpsigrdata, &sig);
    286 	if (ret != ISC_R_SUCCESS)
    287 		goto cleanup_context;
    288 
    289 	dns_fixedname_init(&fnewname);
    290 	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
    291 					NULL) == ISC_R_SUCCESS);
    292 	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
    293 
    294 	/*
    295 	 * Create an envelope for each rdata: <name|type|class|ttl>.
    296 	 */
    297 	isc_buffer_init(&envbuf, data, sizeof(data));
    298 	memmove(data, r.base, r.length);
    299 	isc_buffer_add(&envbuf, r.length);
    300 	isc_buffer_putuint16(&envbuf, set->type);
    301 	isc_buffer_putuint16(&envbuf, set->rdclass);
    302 	isc_buffer_putuint32(&envbuf, set->ttl);
    303 
    304 	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
    305 	if (ret != ISC_R_SUCCESS)
    306 		goto cleanup_context;
    307 	isc_buffer_usedregion(&envbuf, &r);
    308 
    309 	for (i = 0; i < nrdatas; i++) {
    310 		uint16_t len;
    311 		isc_buffer_t lenbuf;
    312 		isc_region_t lenr;
    313 
    314 		/*
    315 		 * Skip duplicates.
    316 		 */
    317 		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
    318 		    continue;
    319 
    320 		/*
    321 		 * Digest the envelope.
    322 		 */
    323 		ret = dst_context_adddata(ctx, &r);
    324 		if (ret != ISC_R_SUCCESS)
    325 			goto cleanup_array;
    326 
    327 		/*
    328 		 * Digest the length of the rdata.
    329 		 */
    330 		isc_buffer_init(&lenbuf, &len, sizeof(len));
    331 		INSIST(rdatas[i].length < 65536);
    332 		isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length);
    333 		isc_buffer_usedregion(&lenbuf, &lenr);
    334 		ret = dst_context_adddata(ctx, &lenr);
    335 		if (ret != ISC_R_SUCCESS)
    336 			goto cleanup_array;
    337 
    338 		/*
    339 		 * Digest the rdata.
    340 		 */
    341 		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
    342 		if (ret != ISC_R_SUCCESS)
    343 			goto cleanup_array;
    344 	}
    345 
    346 	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
    347 	ret = dst_context_sign(ctx, &sigbuf);
    348 	if (ret != ISC_R_SUCCESS)
    349 		goto cleanup_array;
    350 	isc_buffer_usedregion(&sigbuf, &r);
    351 	if (r.length != sig.siglen) {
    352 		ret = ISC_R_NOSPACE;
    353 		goto cleanup_array;
    354 	}
    355 
    356 	ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
    357 				  sig.common.rdtype, &sig, buffer);
    358 
    359 cleanup_array:
    360 	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
    361 cleanup_context:
    362 	dst_context_destroy(&ctx);
    363 cleanup_databuf:
    364 	isc_buffer_free(&databuf);
    365 cleanup_signature:
    366 	isc_mem_put(mctx, sig.signature, sig.siglen);
    367 
    368 	return (ret);
    369 }
    370 
    371 isc_result_t
    372 dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
    373 		  bool ignoretime, unsigned int maxbits,
    374 		  isc_mem_t *mctx, dns_rdata_t *sigrdata, dns_name_t *wild)
    375 {
    376 	dns_rdata_rrsig_t sig;
    377 	dns_fixedname_t fnewname;
    378 	isc_region_t r;
    379 	isc_buffer_t envbuf;
    380 	dns_rdata_t *rdatas;
    381 	int nrdatas, i;
    382 	isc_stdtime_t now;
    383 	isc_result_t ret;
    384 	unsigned char data[300];
    385 	dst_context_t *ctx = NULL;
    386 	int labels = 0;
    387 	uint32_t flags;
    388 	bool downcase = false;
    389 
    390 	REQUIRE(name != NULL);
    391 	REQUIRE(set != NULL);
    392 	REQUIRE(key != NULL);
    393 	REQUIRE(mctx != NULL);
    394 	REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
    395 
    396 	ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
    397 	if (ret != ISC_R_SUCCESS)
    398 		return (ret);
    399 
    400 	if (set->type != sig.covered)
    401 		return (DNS_R_SIGINVALID);
    402 
    403 	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
    404 		inc_stat(dns_dnssecstats_fail);
    405 		return (DNS_R_SIGINVALID);
    406 	}
    407 
    408 	if (!ignoretime) {
    409 		isc_stdtime_get(&now);
    410 
    411 		/*
    412 		 * Is SIG temporally valid?
    413 		 */
    414 		if (isc_serial_lt((uint32_t)now, sig.timesigned)) {
    415 			inc_stat(dns_dnssecstats_fail);
    416 			return (DNS_R_SIGFUTURE);
    417 		} else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) {
    418 			inc_stat(dns_dnssecstats_fail);
    419 			return (DNS_R_SIGEXPIRED);
    420 		}
    421 	}
    422 
    423 	/*
    424 	 * NS, SOA and DNSSKEY records are signed by their owner.
    425 	 * DS records are signed by the parent.
    426 	 */
    427 	switch (set->type) {
    428 	case dns_rdatatype_ns:
    429 	case dns_rdatatype_soa:
    430 	case dns_rdatatype_dnskey:
    431 		if (!dns_name_equal(name, &sig.signer)) {
    432 			inc_stat(dns_dnssecstats_fail);
    433 			return (DNS_R_SIGINVALID);
    434 		}
    435 		break;
    436 	case dns_rdatatype_ds:
    437 		if (dns_name_equal(name, &sig.signer)) {
    438 			inc_stat(dns_dnssecstats_fail);
    439 			return (DNS_R_SIGINVALID);
    440 		}
    441 		/* FALLTHROUGH */
    442 	default:
    443 		if (!dns_name_issubdomain(name, &sig.signer)) {
    444 			inc_stat(dns_dnssecstats_fail);
    445 			return (DNS_R_SIGINVALID);
    446 		}
    447 		break;
    448 	}
    449 
    450 	/*
    451 	 * Is the key allowed to sign data?
    452 	 */
    453 	flags = dst_key_flags(key);
    454 	if ((flags & DNS_KEYTYPE_NOAUTH) != 0) {
    455 		inc_stat(dns_dnssecstats_fail);
    456 		return (DNS_R_KEYUNAUTHORIZED);
    457 	}
    458 	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
    459 		inc_stat(dns_dnssecstats_fail);
    460 		return (DNS_R_KEYUNAUTHORIZED);
    461 	}
    462 
    463  again:
    464 	ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC,
    465 				 false, maxbits, &ctx);
    466 	if (ret != ISC_R_SUCCESS)
    467 		goto cleanup_struct;
    468 
    469 	/*
    470 	 * Digest the SIG rdata (not including the signature).
    471 	 */
    472 	ret = digest_sig(ctx, downcase, sigrdata, &sig);
    473 	if (ret != ISC_R_SUCCESS)
    474 		goto cleanup_context;
    475 
    476 	/*
    477 	 * If the name is an expanded wildcard, use the wildcard name.
    478 	 */
    479 	dns_fixedname_init(&fnewname);
    480 	labels = dns_name_countlabels(name) - 1;
    481 	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
    482 					NULL) == ISC_R_SUCCESS);
    483 	if (labels - sig.labels > 0)
    484 		dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
    485 			       NULL, dns_fixedname_name(&fnewname));
    486 
    487 	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
    488 
    489 	/*
    490 	 * Create an envelope for each rdata: <name|type|class|ttl>.
    491 	 */
    492 	isc_buffer_init(&envbuf, data, sizeof(data));
    493 	if (labels - sig.labels > 0) {
    494 		isc_buffer_putuint8(&envbuf, 1);
    495 		isc_buffer_putuint8(&envbuf, '*');
    496 		memmove(data + 2, r.base, r.length);
    497 	}
    498 	else
    499 		memmove(data, r.base, r.length);
    500 	isc_buffer_add(&envbuf, r.length);
    501 	isc_buffer_putuint16(&envbuf, set->type);
    502 	isc_buffer_putuint16(&envbuf, set->rdclass);
    503 	isc_buffer_putuint32(&envbuf, sig.originalttl);
    504 
    505 	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
    506 	if (ret != ISC_R_SUCCESS)
    507 		goto cleanup_context;
    508 
    509 	isc_buffer_usedregion(&envbuf, &r);
    510 
    511 	for (i = 0; i < nrdatas; i++) {
    512 		uint16_t len;
    513 		isc_buffer_t lenbuf;
    514 		isc_region_t lenr;
    515 
    516 		/*
    517 		 * Skip duplicates.
    518 		 */
    519 		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
    520 		    continue;
    521 
    522 		/*
    523 		 * Digest the envelope.
    524 		 */
    525 		ret = dst_context_adddata(ctx, &r);
    526 		if (ret != ISC_R_SUCCESS)
    527 			goto cleanup_array;
    528 
    529 		/*
    530 		 * Digest the rdata length.
    531 		 */
    532 		isc_buffer_init(&lenbuf, &len, sizeof(len));
    533 		INSIST(rdatas[i].length < 65536);
    534 		isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length);
    535 		isc_buffer_usedregion(&lenbuf, &lenr);
    536 
    537 		/*
    538 		 * Digest the rdata.
    539 		 */
    540 		ret = dst_context_adddata(ctx, &lenr);
    541 		if (ret != ISC_R_SUCCESS)
    542 			goto cleanup_array;
    543 		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
    544 		if (ret != ISC_R_SUCCESS)
    545 			goto cleanup_array;
    546 	}
    547 
    548 	r.base = sig.signature;
    549 	r.length = sig.siglen;
    550 	ret = dst_context_verify2(ctx, maxbits, &r);
    551 	if (ret == ISC_R_SUCCESS && downcase) {
    552 		char namebuf[DNS_NAME_FORMATSIZE];
    553 		dns_name_format(&sig.signer, namebuf, sizeof(namebuf));
    554 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
    555 			      DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
    556 			      "successfully validated after lower casing "
    557 			      "signer '%s'", namebuf);
    558 		inc_stat(dns_dnssecstats_downcase);
    559 	} else if (ret == ISC_R_SUCCESS)
    560 		inc_stat(dns_dnssecstats_asis);
    561 
    562 cleanup_array:
    563 	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
    564 cleanup_context:
    565 	dst_context_destroy(&ctx);
    566 	if (ret == DST_R_VERIFYFAILURE && !downcase) {
    567 		downcase = true;
    568 		goto again;
    569 	}
    570 cleanup_struct:
    571 	dns_rdata_freestruct(&sig);
    572 
    573 	if (ret == DST_R_VERIFYFAILURE)
    574 		ret = DNS_R_SIGINVALID;
    575 
    576 	if (ret != ISC_R_SUCCESS)
    577 		inc_stat(dns_dnssecstats_fail);
    578 
    579 	if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
    580 		if (wild != NULL)
    581 			RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
    582 						 dns_fixedname_name(&fnewname),
    583 						 wild, NULL) == ISC_R_SUCCESS);
    584 		inc_stat(dns_dnssecstats_wildcard);
    585 		ret = DNS_R_FROMWILDCARD;
    586 	}
    587 	return (ret);
    588 }
    589 
    590 bool
    591 dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
    592 	isc_result_t result;
    593 	isc_stdtime_t publish, active, revoke, inactive, deltime;
    594 	bool pubset = false, actset = false;
    595 	bool revset = false, inactset = false;
    596 	bool delset = false;
    597 	int major, minor;
    598 
    599 	/* Is this an old-style key? */
    600 	result = dst_key_getprivateformat(key, &major, &minor);
    601 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
    602 
    603 	/*
    604 	 * Smart signing started with key format 1.3; prior to that, all
    605 	 * keys are assumed active
    606 	 */
    607 	if (major == 1 && minor <= 2)
    608 		return (true);
    609 
    610 	result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
    611 	if (result == ISC_R_SUCCESS)
    612 		pubset = true;
    613 
    614 	result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
    615 	if (result == ISC_R_SUCCESS)
    616 		actset = true;
    617 
    618 	result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
    619 	if (result == ISC_R_SUCCESS)
    620 		revset = true;
    621 
    622 	result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
    623 	if (result == ISC_R_SUCCESS)
    624 		inactset = true;
    625 
    626 	result = dst_key_gettime(key, DST_TIME_DELETE, &deltime);
    627 	if (result == ISC_R_SUCCESS)
    628 		delset = true;
    629 
    630 	if ((inactset && inactive <= now) || (delset && deltime <= now))
    631 		return (false);
    632 
    633 	if (revset && revoke <= now && pubset && publish <= now)
    634 		return (true);
    635 
    636 	if (actset && active <= now)
    637 		return (true);
    638 
    639 	return (false);
    640 }
    641 
    642 /*%<
    643  * Indicate whether a key is scheduled to to have CDS/CDNSKEY records
    644  * published now.
    645  *
    646  * Returns true iff.
    647  *  - SyncPublish is set and in the past, AND
    648  *  - SyncDelete is unset or in the future
    649  */
    650 static bool
    651 syncpublish(dst_key_t *key, isc_stdtime_t now) {
    652 	isc_result_t result;
    653 	isc_stdtime_t when;
    654 	int major, minor;
    655 
    656 	/*
    657 	 * Is this an old-style key?
    658 	 */
    659 	result = dst_key_getprivateformat(key, &major, &minor);
    660 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
    661 
    662 	/*
    663 	 * Smart signing started with key format 1.3
    664 	 */
    665 	if (major == 1 && minor <= 2)
    666 		return (false);
    667 
    668 	result = dst_key_gettime(key, DST_TIME_SYNCPUBLISH, &when);
    669 	if (result != ISC_R_SUCCESS)
    670 		return (false);
    671 
    672 	result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
    673 	if (result != ISC_R_SUCCESS)
    674 		return (true);
    675 	if (when <= now)
    676 		return (false);
    677 	return (true);
    678 }
    679 
    680 /*%<
    681  * Indicate whether a key is scheduled to to have CDS/CDNSKEY records
    682  * deleted now.
    683  *
    684  * Returns true iff. SyncDelete is set and in the past.
    685  */
    686 static bool
    687 syncdelete(dst_key_t *key, isc_stdtime_t now) {
    688 	isc_result_t result;
    689 	isc_stdtime_t when;
    690 	int major, minor;
    691 
    692 	/*
    693 	 * Is this an old-style key?
    694 	 */
    695 	result = dst_key_getprivateformat(key, &major, &minor);
    696 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
    697 
    698 	/*
    699 	 * Smart signing started with key format 1.3.
    700 	 */
    701 	if (major == 1 && minor <= 2)
    702 		return (false);
    703 
    704 	result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
    705 	if (result != ISC_R_SUCCESS)
    706 		return (false);
    707 	if (when <= now)
    708 		return (true);
    709 	return (false);
    710 }
    711 
    712 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
    713 			  == DNS_KEYOWNER_ZONE)
    714 
    715 isc_result_t
    716 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
    717 			dns_dbnode_t *node, const dns_name_t *name,
    718 			const char *directory, isc_stdtime_t now,
    719 			isc_mem_t *mctx, unsigned int maxkeys,
    720 			dst_key_t **keys, unsigned int *nkeys)
    721 {
    722 	dns_rdataset_t rdataset;
    723 	dns_rdata_t rdata = DNS_RDATA_INIT;
    724 	isc_result_t result;
    725 	dst_key_t *pubkey = NULL;
    726 	unsigned int count = 0;
    727 
    728 	REQUIRE(nkeys != NULL);
    729 	REQUIRE(keys != NULL);
    730 
    731 	*nkeys = 0;
    732 	memset(keys, 0, sizeof(*keys) * maxkeys);
    733 	dns_rdataset_init(&rdataset);
    734 	RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
    735 				   &rdataset, NULL));
    736 	RETERR(dns_rdataset_first(&rdataset));
    737 	while (result == ISC_R_SUCCESS && count < maxkeys) {
    738 		pubkey = NULL;
    739 		dns_rdataset_current(&rdataset, &rdata);
    740 		RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
    741 		dst_key_setttl(pubkey, rdataset.ttl);
    742 
    743 		if (!is_zone_key(pubkey) ||
    744 		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
    745 			goto next;
    746 		/* Corrupted .key file? */
    747 		if (!dns_name_equal(name, dst_key_name(pubkey)))
    748 			goto next;
    749 		keys[count] = NULL;
    750 		result = dst_key_fromfile(dst_key_name(pubkey),
    751 					  dst_key_id(pubkey),
    752 					  dst_key_alg(pubkey),
    753 					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
    754 					  directory,
    755 					  mctx, &keys[count]);
    756 
    757 		/*
    758 		 * If the key was revoked and the private file
    759 		 * doesn't exist, maybe it was revoked internally
    760 		 * by named.  Try loading the unrevoked version.
    761 		 */
    762 		if (result == ISC_R_FILENOTFOUND) {
    763 			uint32_t flags;
    764 			flags = dst_key_flags(pubkey);
    765 			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
    766 				dst_key_setflags(pubkey,
    767 						 flags & ~DNS_KEYFLAG_REVOKE);
    768 				result = dst_key_fromfile(dst_key_name(pubkey),
    769 							  dst_key_id(pubkey),
    770 							  dst_key_alg(pubkey),
    771 							  DST_TYPE_PUBLIC|
    772 							  DST_TYPE_PRIVATE,
    773 							  directory,
    774 							  mctx, &keys[count]);
    775 				if (result == ISC_R_SUCCESS &&
    776 				    dst_key_pubcompare(pubkey, keys[count],
    777 						       false)) {
    778 					dst_key_setflags(keys[count], flags);
    779 				}
    780 				dst_key_setflags(pubkey, flags);
    781 			}
    782 		}
    783 
    784 		if (result != ISC_R_SUCCESS) {
    785 			char filename[DNS_NAME_FORMATSIZE +
    786 				      DNS_SECALG_FORMATSIZE +
    787 				      sizeof("key file for //65535")];
    788 			isc_result_t result2;
    789 			isc_buffer_t buf;
    790 
    791 			isc_buffer_init(&buf, filename, NAME_MAX);
    792 			result2 = dst_key_getfilename(dst_key_name(pubkey),
    793 						      dst_key_id(pubkey),
    794 						      dst_key_alg(pubkey),
    795 						      (DST_TYPE_PUBLIC |
    796 						       DST_TYPE_PRIVATE),
    797 						      directory, mctx,
    798 						      &buf);
    799 			if (result2 != ISC_R_SUCCESS) {
    800 				char namebuf[DNS_NAME_FORMATSIZE];
    801 				char algbuf[DNS_SECALG_FORMATSIZE];
    802 
    803 				dns_name_format(dst_key_name(pubkey),
    804 						namebuf, sizeof(namebuf));
    805 				dns_secalg_format(dst_key_alg(pubkey),
    806 						  algbuf, sizeof(algbuf));
    807 				snprintf(filename, sizeof(filename) - 1,
    808 					 "key file for %s/%s/%d",
    809 					 namebuf, algbuf, dst_key_id(pubkey));
    810 			}
    811 
    812 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
    813 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
    814 				      "dns_dnssec_findzonekeys2: error "
    815 				      "reading %s: %s",
    816 				      filename, isc_result_totext(result));
    817 		}
    818 
    819 		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
    820 			keys[count] = pubkey;
    821 			pubkey = NULL;
    822 			count++;
    823 			goto next;
    824 		}
    825 
    826 		if (result != ISC_R_SUCCESS)
    827 			goto failure;
    828 
    829 		/*
    830 		 * If a key is marked inactive, skip it
    831 		 */
    832 		if (!dns_dnssec_keyactive(keys[count], now)) {
    833 			dst_key_setinactive(pubkey, true);
    834 			dst_key_free(&keys[count]);
    835 			keys[count] = pubkey;
    836 			pubkey = NULL;
    837 			count++;
    838 			goto next;
    839 		}
    840 
    841 		/*
    842 		 * Whatever the key's default TTL may have
    843 		 * been, the rdataset TTL takes priority.
    844 		 */
    845 		dst_key_setttl(keys[count], rdataset.ttl);
    846 
    847 		if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
    848 			/* We should never get here. */
    849 			dst_key_free(&keys[count]);
    850 			goto next;
    851 		}
    852 		count++;
    853  next:
    854 		if (pubkey != NULL)
    855 			dst_key_free(&pubkey);
    856 		dns_rdata_reset(&rdata);
    857 		result = dns_rdataset_next(&rdataset);
    858 	}
    859 	if (result != ISC_R_NOMORE)
    860 		goto failure;
    861 	if (count == 0)
    862 		result = ISC_R_NOTFOUND;
    863 	else
    864 		result = ISC_R_SUCCESS;
    865 
    866  failure:
    867 	if (dns_rdataset_isassociated(&rdataset))
    868 		dns_rdataset_disassociate(&rdataset);
    869 	if (pubkey != NULL)
    870 		dst_key_free(&pubkey);
    871 	if (result != ISC_R_SUCCESS)
    872 		while (count > 0)
    873 			dst_key_free(&keys[--count]);
    874 	*nkeys = count;
    875 	return (result);
    876 }
    877 
    878 isc_result_t
    879 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
    880 	dns_rdata_sig_t sig;	/* SIG(0) */
    881 	unsigned char data[512];
    882 	unsigned char header[DNS_MESSAGE_HEADERLEN];
    883 	isc_buffer_t headerbuf, databuf, sigbuf;
    884 	unsigned int sigsize;
    885 	isc_buffer_t *dynbuf = NULL;
    886 	dns_rdata_t *rdata;
    887 	dns_rdatalist_t *datalist;
    888 	dns_rdataset_t *dataset;
    889 	isc_region_t r;
    890 	isc_stdtime_t now;
    891 	dst_context_t *ctx = NULL;
    892 	isc_mem_t *mctx;
    893 	isc_result_t result;
    894 	bool signeedsfree = true;
    895 
    896 	REQUIRE(msg != NULL);
    897 	REQUIRE(key != NULL);
    898 
    899 	if (is_response(msg))
    900 		REQUIRE(msg->query.base != NULL);
    901 
    902 	mctx = msg->mctx;
    903 
    904 	memset(&sig, 0, sizeof(sig));
    905 
    906 	sig.mctx = mctx;
    907 	sig.common.rdclass = dns_rdataclass_any;
    908 	sig.common.rdtype = dns_rdatatype_sig;	/* SIG(0) */
    909 	ISC_LINK_INIT(&sig.common, link);
    910 
    911 	sig.covered = 0;
    912 	sig.algorithm = dst_key_alg(key);
    913 	sig.labels = 0; /* the root name */
    914 	sig.originalttl = 0;
    915 
    916 	isc_stdtime_get(&now);
    917 	sig.timesigned = now - DNS_TSIG_FUDGE;
    918 	sig.timeexpire = now + DNS_TSIG_FUDGE;
    919 
    920 	sig.keyid = dst_key_id(key);
    921 
    922 	dns_name_init(&sig.signer, NULL);
    923 	dns_name_clone(dst_key_name(key), &sig.signer);
    924 
    925 	sig.siglen = 0;
    926 	sig.signature = NULL;
    927 
    928 	isc_buffer_init(&databuf, data, sizeof(data));
    929 
    930 	RETERR(dst_context_create(key, mctx,
    931 				  DNS_LOGCATEGORY_DNSSEC, true, 0, &ctx));
    932 
    933 	/*
    934 	 * Digest the fields of the SIG - we can cheat and use
    935 	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
    936 	 * is identical to dns format.
    937 	 */
    938 	RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
    939 				    dns_rdatatype_sig /* SIG(0) */,
    940 				    &sig, &databuf));
    941 	isc_buffer_usedregion(&databuf, &r);
    942 	RETERR(dst_context_adddata(ctx, &r));
    943 
    944 	/*
    945 	 * If this is a response, digest the query.
    946 	 */
    947 	if (is_response(msg))
    948 		RETERR(dst_context_adddata(ctx, &msg->query));
    949 
    950 	/*
    951 	 * Digest the header.
    952 	 */
    953 	isc_buffer_init(&headerbuf, header, sizeof(header));
    954 	dns_message_renderheader(msg, &headerbuf);
    955 	isc_buffer_usedregion(&headerbuf, &r);
    956 	RETERR(dst_context_adddata(ctx, &r));
    957 
    958 	/*
    959 	 * Digest the remainder of the message.
    960 	 */
    961 	isc_buffer_usedregion(msg->buffer, &r);
    962 	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
    963 	RETERR(dst_context_adddata(ctx, &r));
    964 
    965 	RETERR(dst_key_sigsize(key, &sigsize));
    966 	sig.siglen = sigsize;
    967 	sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
    968 	if (sig.signature == NULL) {
    969 		result = ISC_R_NOMEMORY;
    970 		goto failure;
    971 	}
    972 
    973 	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
    974 	RETERR(dst_context_sign(ctx, &sigbuf));
    975 	dst_context_destroy(&ctx);
    976 
    977 	rdata = NULL;
    978 	RETERR(dns_message_gettemprdata(msg, &rdata));
    979 	RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
    980 	RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
    981 				    dns_rdatatype_sig /* SIG(0) */,
    982 				    &sig, dynbuf));
    983 
    984 	isc_mem_put(mctx, sig.signature, sig.siglen);
    985 	signeedsfree = false;
    986 
    987 	dns_message_takebuffer(msg, &dynbuf);
    988 
    989 	datalist = NULL;
    990 	RETERR(dns_message_gettemprdatalist(msg, &datalist));
    991 	datalist->rdclass = dns_rdataclass_any;
    992 	datalist->type = dns_rdatatype_sig;	/* SIG(0) */
    993 	ISC_LIST_APPEND(datalist->rdata, rdata, link);
    994 	dataset = NULL;
    995 	RETERR(dns_message_gettemprdataset(msg, &dataset));
    996 	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
    997 	msg->sig0 = dataset;
    998 
    999 	return (ISC_R_SUCCESS);
   1000 
   1001 failure:
   1002 	if (dynbuf != NULL)
   1003 		isc_buffer_free(&dynbuf);
   1004 	if (signeedsfree)
   1005 		isc_mem_put(mctx, sig.signature, sig.siglen);
   1006 	if (ctx != NULL)
   1007 		dst_context_destroy(&ctx);
   1008 
   1009 	return (result);
   1010 }
   1011 
   1012 isc_result_t
   1013 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
   1014 			 dst_key_t *key)
   1015 {
   1016 	dns_rdata_sig_t sig;	/* SIG(0) */
   1017 	unsigned char header[DNS_MESSAGE_HEADERLEN];
   1018 	dns_rdata_t rdata = DNS_RDATA_INIT;
   1019 	isc_region_t r, source_r, sig_r, header_r;
   1020 	isc_stdtime_t now;
   1021 	dst_context_t *ctx = NULL;
   1022 	isc_mem_t *mctx;
   1023 	isc_result_t result;
   1024 	uint16_t addcount, addcount_n;
   1025 	bool signeedsfree = false;
   1026 
   1027 	REQUIRE(source != NULL);
   1028 	REQUIRE(msg != NULL);
   1029 	REQUIRE(key != NULL);
   1030 
   1031 	mctx = msg->mctx;
   1032 
   1033 	msg->verify_attempted = 1;
   1034 	msg->verified_sig = 0;
   1035 	msg->sig0status = dns_tsigerror_badsig;
   1036 
   1037 	if (is_response(msg)) {
   1038 		if (msg->query.base == NULL)
   1039 			return (DNS_R_UNEXPECTEDTSIG);
   1040 	}
   1041 
   1042 	isc_buffer_usedregion(source, &source_r);
   1043 
   1044 	RETERR(dns_rdataset_first(msg->sig0));
   1045 	dns_rdataset_current(msg->sig0, &rdata);
   1046 
   1047 	RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
   1048 	signeedsfree = true;
   1049 
   1050 	if (sig.labels != 0) {
   1051 		result = DNS_R_SIGINVALID;
   1052 		goto failure;
   1053 	}
   1054 
   1055 	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
   1056 		result = DNS_R_SIGINVALID;
   1057 		msg->sig0status = dns_tsigerror_badtime;
   1058 		goto failure;
   1059 	}
   1060 
   1061 	isc_stdtime_get(&now);
   1062 	if (isc_serial_lt((uint32_t)now, sig.timesigned)) {
   1063 		result = DNS_R_SIGFUTURE;
   1064 		msg->sig0status = dns_tsigerror_badtime;
   1065 		goto failure;
   1066 	}
   1067 	else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) {
   1068 		result = DNS_R_SIGEXPIRED;
   1069 		msg->sig0status = dns_tsigerror_badtime;
   1070 		goto failure;
   1071 	}
   1072 
   1073 	if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
   1074 		result = DNS_R_SIGINVALID;
   1075 		msg->sig0status = dns_tsigerror_badkey;
   1076 		goto failure;
   1077 	}
   1078 
   1079 	RETERR(dst_context_create(key, mctx,
   1080 				  DNS_LOGCATEGORY_DNSSEC, false, 0, &ctx));
   1081 
   1082 	/*
   1083 	 * Digest the SIG(0) record, except for the signature.
   1084 	 */
   1085 	dns_rdata_toregion(&rdata, &r);
   1086 	r.length -= sig.siglen;
   1087 	RETERR(dst_context_adddata(ctx, &r));
   1088 
   1089 	/*
   1090 	 * If this is a response, digest the query.
   1091 	 */
   1092 	if (is_response(msg))
   1093 		RETERR(dst_context_adddata(ctx, &msg->query));
   1094 
   1095 	/*
   1096 	 * Extract the header.
   1097 	 */
   1098 	memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN);
   1099 
   1100 	/*
   1101 	 * Decrement the additional field counter.
   1102 	 */
   1103 	memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
   1104 	addcount_n = ntohs(addcount);
   1105 	addcount = htons((uint16_t)(addcount_n - 1));
   1106 	memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
   1107 
   1108 	/*
   1109 	 * Digest the modified header.
   1110 	 */
   1111 	header_r.base = (unsigned char *) header;
   1112 	header_r.length = DNS_MESSAGE_HEADERLEN;
   1113 	RETERR(dst_context_adddata(ctx, &header_r));
   1114 
   1115 	/*
   1116 	 * Digest all non-SIG(0) records.
   1117 	 */
   1118 	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
   1119 	r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
   1120 	RETERR(dst_context_adddata(ctx, &r));
   1121 
   1122 	sig_r.base = sig.signature;
   1123 	sig_r.length = sig.siglen;
   1124 	result = dst_context_verify(ctx, &sig_r);
   1125 	if (result != ISC_R_SUCCESS) {
   1126 		msg->sig0status = dns_tsigerror_badsig;
   1127 		goto failure;
   1128 	}
   1129 
   1130 	msg->verified_sig = 1;
   1131 	msg->sig0status = dns_rcode_noerror;
   1132 
   1133 	dst_context_destroy(&ctx);
   1134 	dns_rdata_freestruct(&sig);
   1135 
   1136 	return (ISC_R_SUCCESS);
   1137 
   1138 failure:
   1139 	if (signeedsfree)
   1140 		dns_rdata_freestruct(&sig);
   1141 	if (ctx != NULL)
   1142 		dst_context_destroy(&ctx);
   1143 
   1144 	return (result);
   1145 }
   1146 
   1147 /*%
   1148  * Does this key ('rdata') self sign the rrset ('rdataset')?
   1149  */
   1150 bool
   1151 dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name,
   1152 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
   1153 		     bool ignoretime, isc_mem_t *mctx)
   1154 {
   1155 	INSIST(rdataset->type == dns_rdatatype_key ||
   1156 	       rdataset->type == dns_rdatatype_dnskey);
   1157 	if (rdataset->type == dns_rdatatype_key) {
   1158 		INSIST(sigrdataset->type == dns_rdatatype_sig);
   1159 		INSIST(sigrdataset->covers == dns_rdatatype_key);
   1160 	} else {
   1161 		INSIST(sigrdataset->type == dns_rdatatype_rrsig);
   1162 		INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
   1163 	}
   1164 
   1165 	return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
   1166 				 ignoretime, mctx));
   1167 
   1168 }
   1169 
   1170 bool
   1171 dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
   1172 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
   1173 		     bool ignoretime, isc_mem_t *mctx)
   1174 {
   1175 	dst_key_t *dstkey = NULL;
   1176 	dns_keytag_t keytag;
   1177 	dns_rdata_dnskey_t key;
   1178 	dns_rdata_rrsig_t sig;
   1179 	dns_rdata_t sigrdata = DNS_RDATA_INIT;
   1180 	isc_result_t result;
   1181 
   1182 	INSIST(sigrdataset->type == dns_rdatatype_rrsig);
   1183 	if (sigrdataset->covers != rdataset->type)
   1184 		return (false);
   1185 
   1186 	result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
   1187 	if (result != ISC_R_SUCCESS)
   1188 		return (false);
   1189 	result = dns_rdata_tostruct(rdata, &key, NULL);
   1190 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1191 
   1192 	keytag = dst_key_id(dstkey);
   1193 	for (result = dns_rdataset_first(sigrdataset);
   1194 	     result == ISC_R_SUCCESS;
   1195 	     result = dns_rdataset_next(sigrdataset))
   1196 	{
   1197 		dns_rdata_reset(&sigrdata);
   1198 		dns_rdataset_current(sigrdataset, &sigrdata);
   1199 		result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
   1200 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1201 
   1202 		if (sig.algorithm == key.algorithm &&
   1203 		    sig.keyid == keytag) {
   1204 			result = dns_dnssec_verify(name, rdataset, dstkey,
   1205 						   ignoretime, 0, mctx,
   1206 						   &sigrdata, NULL);
   1207 			if (result == ISC_R_SUCCESS) {
   1208 				dst_key_free(&dstkey);
   1209 				return (true);
   1210 			}
   1211 		}
   1212 	}
   1213 	dst_key_free(&dstkey);
   1214 	return (false);
   1215 }
   1216 
   1217 isc_result_t
   1218 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
   1219 		     dns_dnsseckey_t **dkp)
   1220 {
   1221 	isc_result_t result;
   1222 	dns_dnsseckey_t *dk;
   1223 	int major, minor;
   1224 
   1225 	REQUIRE(dkp != NULL && *dkp == NULL);
   1226 	dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
   1227 	if (dk == NULL)
   1228 		return (ISC_R_NOMEMORY);
   1229 
   1230 	dk->key = *dstkey;
   1231 	*dstkey = NULL;
   1232 	dk->force_publish = false;
   1233 	dk->force_sign = false;
   1234 	dk->hint_publish = false;
   1235 	dk->hint_sign = false;
   1236 	dk->hint_remove = false;
   1237 	dk->first_sign = false;
   1238 	dk->is_active = false;
   1239 	dk->prepublish = 0;
   1240 	dk->source = dns_keysource_unknown;
   1241 	dk->index = 0;
   1242 
   1243 	/* KSK or ZSK? */
   1244 	dk->ksk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
   1245 
   1246 	/* Is this an old-style key? */
   1247 	result = dst_key_getprivateformat(dk->key, &major, &minor);
   1248 	INSIST(result == ISC_R_SUCCESS);
   1249 
   1250 	/* Smart signing started with key format 1.3 */
   1251 	dk->legacy = (major == 1 && minor <= 2);
   1252 
   1253 	ISC_LINK_INIT(dk, link);
   1254 	*dkp = dk;
   1255 	return (ISC_R_SUCCESS);
   1256 }
   1257 
   1258 void
   1259 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
   1260 	dns_dnsseckey_t *dk;
   1261 
   1262 	REQUIRE(dkp != NULL && *dkp != NULL);
   1263 	dk = *dkp;
   1264 	if (dk->key != NULL)
   1265 		dst_key_free(&dk->key);
   1266 	isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
   1267 	*dkp = NULL;
   1268 }
   1269 
   1270 static void
   1271 get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
   1272 	isc_result_t result;
   1273 	isc_stdtime_t publish, active, revoke, inactive, deltime;
   1274 	bool pubset = false, actset = false;
   1275 	bool revset = false, inactset = false;
   1276 	bool delset = false;
   1277 
   1278 	REQUIRE(key != NULL && key->key != NULL);
   1279 
   1280 	result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
   1281 	if (result == ISC_R_SUCCESS)
   1282 		pubset = true;
   1283 
   1284 	result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
   1285 	if (result == ISC_R_SUCCESS)
   1286 		actset = true;
   1287 
   1288 	result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
   1289 	if (result == ISC_R_SUCCESS)
   1290 		revset = true;
   1291 
   1292 	result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
   1293 	if (result == ISC_R_SUCCESS)
   1294 		inactset = true;
   1295 
   1296 	result = dst_key_gettime(key->key, DST_TIME_DELETE, &deltime);
   1297 	if (result == ISC_R_SUCCESS)
   1298 		delset = true;
   1299 
   1300 	/* Metadata says publish (but possibly not activate) */
   1301 	if (pubset && publish <= now)
   1302 		key->hint_publish = true;
   1303 
   1304 	/* Metadata says activate (so we must also publish) */
   1305 	if (actset && active <= now) {
   1306 		key->hint_sign = true;
   1307 
   1308 		/* Only publish if publish time has already passed. */
   1309 		if (pubset && publish <= now)
   1310 			key->hint_publish = true;
   1311 	}
   1312 
   1313 	/*
   1314 	 * Activation date is set (maybe in the future), but
   1315 	 * publication date isn't. Most likely the user wants to
   1316 	 * publish now and activate later.
   1317 	 */
   1318 	if (actset && !pubset)
   1319 		key->hint_publish = true;
   1320 
   1321 	/*
   1322 	 * If activation date is in the future, make note of how far off
   1323 	 */
   1324 	if (key->hint_publish && actset && active > now) {
   1325 		key->prepublish = active - now;
   1326 	}
   1327 
   1328 	/*
   1329 	 * Key has been marked inactive: we can continue publishing,
   1330 	 * but don't sign.
   1331 	 */
   1332 	if (key->hint_publish && inactset && inactive <= now) {
   1333 		key->hint_sign = false;
   1334 	}
   1335 
   1336 	/*
   1337 	 * Metadata says revoke.  If the key is published,
   1338 	 * we *have to* sign with it per RFC5011--even if it was
   1339 	 * not active before.
   1340 	 *
   1341 	 * If it hasn't already been done, we should also revoke it now.
   1342 	 */
   1343 	if (key->hint_publish && (revset && revoke <= now)) {
   1344 		uint32_t flags;
   1345 		key->hint_sign = true;
   1346 		flags = dst_key_flags(key->key);
   1347 		if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
   1348 			flags |= DNS_KEYFLAG_REVOKE;
   1349 			dst_key_setflags(key->key, flags);
   1350 		}
   1351 	}
   1352 
   1353 	/*
   1354 	 * Metadata says delete, so don't publish this key or sign with it.
   1355 	 */
   1356 	if (delset && deltime <= now) {
   1357 		key->hint_publish = false;
   1358 		key->hint_sign = false;
   1359 		key->hint_remove = true;
   1360 	}
   1361 }
   1362 
   1363 /*%
   1364  * Get a list of DNSSEC keys from the key repository
   1365  */
   1366 isc_result_t
   1367 dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
   1368 			    isc_stdtime_t now, isc_mem_t *mctx,
   1369 			    dns_dnsseckeylist_t *keylist)
   1370 {
   1371 	isc_result_t result = ISC_R_SUCCESS;
   1372 	bool dir_open = false;
   1373 	dns_dnsseckeylist_t list;
   1374 	isc_dir_t dir;
   1375 	dns_dnsseckey_t *key = NULL;
   1376 	dst_key_t *dstkey = NULL;
   1377 	char namebuf[DNS_NAME_FORMATSIZE];
   1378 	isc_buffer_t b;
   1379 	unsigned int len, i, alg;
   1380 
   1381 	REQUIRE(keylist != NULL);
   1382 	ISC_LIST_INIT(list);
   1383 	isc_dir_init(&dir);
   1384 
   1385 	isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
   1386 	RETERR(dns_name_tofilenametext(origin, false, &b));
   1387 	len = isc_buffer_usedlength(&b);
   1388 	namebuf[len] = '\0';
   1389 
   1390 	if (directory == NULL)
   1391 		directory = ".";
   1392 	RETERR(isc_dir_open(&dir, directory));
   1393 	dir_open = true;
   1394 
   1395 	while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
   1396 		if (dir.entry.name[0] != 'K' ||
   1397 		    dir.entry.length < len + 1 ||
   1398 		    dir.entry.name[len + 1] != '+' ||
   1399 		    strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
   1400 			continue;
   1401 
   1402 		alg = 0;
   1403 		for (i = len + 1 + 1; i < dir.entry.length ; i++) {
   1404 			if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
   1405 				break;
   1406 			alg *= 10;
   1407 			alg += dir.entry.name[i] - '0';
   1408 		}
   1409 
   1410 		/*
   1411 		 * Did we not read exactly 3 digits?
   1412 		 * Did we overflow?
   1413 		 * Did we correctly terminate?
   1414 		 */
   1415 		if (i != len + 1 + 1 + 3 || i >= dir.entry.length ||
   1416 		    dir.entry.name[i] != '+')
   1417 			continue;
   1418 
   1419 		for (i++ ; i < dir.entry.length ; i++)
   1420 			if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
   1421 				break;
   1422 
   1423 		/*
   1424 		 * Did we not read exactly 5 more digits?
   1425 		 * Did we overflow?
   1426 		 * Did we correctly terminate?
   1427 		 */
   1428 		if (i != len + 1 + 1 + 3 + 1 + 5 || i >= dir.entry.length ||
   1429 		    strcmp(dir.entry.name + i, ".private") != 0)
   1430 				continue;
   1431 
   1432 		dstkey = NULL;
   1433 		result = dst_key_fromnamedfile(dir.entry.name,
   1434 					       directory,
   1435 					       DST_TYPE_PUBLIC |
   1436 					       DST_TYPE_PRIVATE,
   1437 					       mctx, &dstkey);
   1438 
   1439 		switch (alg) {
   1440 		case DST_ALG_HMACMD5:
   1441 		case DST_ALG_HMACSHA1:
   1442 		case DST_ALG_HMACSHA224:
   1443 		case DST_ALG_HMACSHA256:
   1444 		case DST_ALG_HMACSHA384:
   1445 		case DST_ALG_HMACSHA512:
   1446 			if (result == DST_R_BADKEYTYPE)
   1447 				continue;
   1448 		}
   1449 
   1450 		if (result != ISC_R_SUCCESS) {
   1451 			isc_log_write(dns_lctx,
   1452 				      DNS_LOGCATEGORY_GENERAL,
   1453 				      DNS_LOGMODULE_DNSSEC,
   1454 				      ISC_LOG_WARNING,
   1455 				      "dns_dnssec_findmatchingkeys: "
   1456 				      "error reading key file %s: %s",
   1457 				      dir.entry.name,
   1458 				      isc_result_totext(result));
   1459 			continue;
   1460 		}
   1461 
   1462 		RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
   1463 		key->source = dns_keysource_repository;
   1464 		get_hints(key, now);
   1465 
   1466 		if (key->legacy) {
   1467 			dns_dnsseckey_destroy(mctx, &key);
   1468 		} else {
   1469 			ISC_LIST_APPEND(list, key, link);
   1470 			key = NULL;
   1471 		}
   1472 	}
   1473 
   1474 	if (!ISC_LIST_EMPTY(list)) {
   1475 		result = ISC_R_SUCCESS;
   1476 		ISC_LIST_APPENDLIST(*keylist, list, link);
   1477 	} else
   1478 		result = ISC_R_NOTFOUND;
   1479 
   1480  failure:
   1481 	if (dir_open)
   1482 		isc_dir_close(&dir);
   1483 	INSIST(key == NULL);
   1484 	while ((key = ISC_LIST_HEAD(list)) != NULL) {
   1485 		ISC_LIST_UNLINK(list, key, link);
   1486 		INSIST(key->key != NULL);
   1487 		dst_key_free(&key->key);
   1488 		dns_dnsseckey_destroy(mctx, &key);
   1489 	}
   1490 	if (dstkey != NULL)
   1491 		dst_key_free(&dstkey);
   1492 	return (result);
   1493 }
   1494 
   1495 /*%
   1496  * Add 'newkey' to 'keylist' if it's not already there.
   1497  *
   1498  * If 'savekeys' is true, then we need to preserve all
   1499  * the keys in the keyset, regardless of whether they have
   1500  * metadata indicating they should be deactivated or removed.
   1501  */
   1502 static isc_result_t
   1503 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
   1504        bool savekeys, isc_mem_t *mctx)
   1505 {
   1506 	dns_dnsseckey_t *key;
   1507 	isc_result_t result;
   1508 
   1509 	/* Skip duplicates */
   1510 	for (key = ISC_LIST_HEAD(*keylist);
   1511 	     key != NULL;
   1512 	     key = ISC_LIST_NEXT(key, link)) {
   1513 		if (dst_key_id(key->key) == dst_key_id(*newkey) &&
   1514 		    dst_key_alg(key->key) == dst_key_alg(*newkey) &&
   1515 		    dns_name_equal(dst_key_name(key->key),
   1516 				   dst_key_name(*newkey)))
   1517 			break;
   1518 	}
   1519 
   1520 	if (key != NULL) {
   1521 		/*
   1522 		 * Found a match.  If the old key was only public and the
   1523 		 * new key is private, replace the old one; otherwise
   1524 		 * leave it.  But either way, mark the key as having
   1525 		 * been found in the zone.
   1526 		 */
   1527 		if (dst_key_isprivate(key->key)) {
   1528 			dst_key_free(newkey);
   1529 		} else if (dst_key_isprivate(*newkey)) {
   1530 			dst_key_free(&key->key);
   1531 			key->key = *newkey;
   1532 		}
   1533 
   1534 		key->source = dns_keysource_zoneapex;
   1535 		return (ISC_R_SUCCESS);
   1536 	}
   1537 
   1538 	result = dns_dnsseckey_create(mctx, newkey, &key);
   1539 	if (result != ISC_R_SUCCESS)
   1540 		return (result);
   1541 	if (key->legacy || savekeys) {
   1542 		key->force_publish = true;
   1543 		key->force_sign = dst_key_isprivate(key->key);
   1544 	}
   1545 	key->source = dns_keysource_zoneapex;
   1546 	ISC_LIST_APPEND(*keylist, key, link);
   1547 	*newkey = NULL;
   1548 	return (ISC_R_SUCCESS);
   1549 }
   1550 
   1551 
   1552 /*%
   1553  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
   1554  * for future reference.
   1555  */
   1556 static isc_result_t
   1557 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
   1558 	isc_result_t result = ISC_R_SUCCESS;
   1559 	dns_rdata_t rdata = DNS_RDATA_INIT;
   1560 	dns_rdataset_t sigs;
   1561 	dns_dnsseckey_t *key;
   1562 
   1563 	REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
   1564 
   1565 	dns_rdataset_init(&sigs);
   1566 	dns_rdataset_clone(rrsigs, &sigs);
   1567 	for (key = ISC_LIST_HEAD(*keylist);
   1568 	     key != NULL;
   1569 	     key = ISC_LIST_NEXT(key, link)) {
   1570 		uint16_t keyid, sigid;
   1571 		dns_secalg_t keyalg, sigalg;
   1572 		keyid = dst_key_id(key->key);
   1573 		keyalg = dst_key_alg(key->key);
   1574 
   1575 		for (result = dns_rdataset_first(&sigs);
   1576 		     result == ISC_R_SUCCESS;
   1577 		     result = dns_rdataset_next(&sigs)) {
   1578 			dns_rdata_rrsig_t sig;
   1579 
   1580 			dns_rdata_reset(&rdata);
   1581 			dns_rdataset_current(&sigs, &rdata);
   1582 			result = dns_rdata_tostruct(&rdata, &sig, NULL);
   1583 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1584 			sigalg = sig.algorithm;
   1585 			sigid = sig.keyid;
   1586 			if (keyid == sigid && keyalg == sigalg) {
   1587 				key->is_active = true;
   1588 				break;
   1589 			}
   1590 		}
   1591 	}
   1592 
   1593 	if (result == ISC_R_NOMORE)
   1594 		result = ISC_R_SUCCESS;
   1595 
   1596 	if (dns_rdataset_isassociated(&sigs))
   1597 		dns_rdataset_disassociate(&sigs);
   1598 	return (result);
   1599 }
   1600 
   1601 /*%
   1602  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
   1603  */
   1604 isc_result_t
   1605 dns_dnssec_keylistfromrdataset(const dns_name_t *origin,
   1606 			       const char *directory, isc_mem_t *mctx,
   1607 			       dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
   1608 			       dns_rdataset_t *soasigs, bool savekeys,
   1609 			       bool publickey,
   1610 			       dns_dnsseckeylist_t *keylist)
   1611 {
   1612 	dns_rdataset_t keys;
   1613 	dns_rdata_t rdata = DNS_RDATA_INIT;
   1614 	dst_key_t *pubkey = NULL, *privkey = NULL;
   1615 	isc_result_t result;
   1616 
   1617 	REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
   1618 
   1619 	dns_rdataset_init(&keys);
   1620 
   1621 	dns_rdataset_clone(keyset, &keys);
   1622 	for (result = dns_rdataset_first(&keys);
   1623 	     result == ISC_R_SUCCESS;
   1624 	     result = dns_rdataset_next(&keys)) {
   1625 		dns_rdata_reset(&rdata);
   1626 		dns_rdataset_current(&keys, &rdata);
   1627 
   1628 		REQUIRE(rdata.type == dns_rdatatype_key ||
   1629 			rdata.type == dns_rdatatype_dnskey);
   1630 		REQUIRE(rdata.length > 3);
   1631 
   1632 		/* Skip unsupported algorithms */
   1633 		if (!dst_algorithm_supported(rdata.data[3]))
   1634 			goto skip;
   1635 
   1636 		RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
   1637 		dst_key_setttl(pubkey, keys.ttl);
   1638 
   1639 		if (!is_zone_key(pubkey) ||
   1640 		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
   1641 			goto skip;
   1642 
   1643 		/* Corrupted .key file? */
   1644 		if (!dns_name_equal(origin, dst_key_name(pubkey)))
   1645 			goto skip;
   1646 
   1647 		if (publickey) {
   1648 			RETERR(addkey(keylist, &pubkey, savekeys, mctx));
   1649 			goto skip;
   1650 		}
   1651 
   1652 		result = dst_key_fromfile(dst_key_name(pubkey),
   1653 					  dst_key_id(pubkey),
   1654 					  dst_key_alg(pubkey),
   1655 					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
   1656 					  directory, mctx, &privkey);
   1657 
   1658 		/*
   1659 		 * If the key was revoked and the private file
   1660 		 * doesn't exist, maybe it was revoked internally
   1661 		 * by named.  Try loading the unrevoked version.
   1662 		 */
   1663 		if (result == ISC_R_FILENOTFOUND) {
   1664 			uint32_t flags;
   1665 			flags = dst_key_flags(pubkey);
   1666 			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
   1667 				dst_key_setflags(pubkey,
   1668 						 flags & ~DNS_KEYFLAG_REVOKE);
   1669 				result = dst_key_fromfile(dst_key_name(pubkey),
   1670 							  dst_key_id(pubkey),
   1671 							  dst_key_alg(pubkey),
   1672 							  DST_TYPE_PUBLIC|
   1673 							  DST_TYPE_PRIVATE,
   1674 							  directory,
   1675 							  mctx, &privkey);
   1676 				if (result == ISC_R_SUCCESS &&
   1677 				    dst_key_pubcompare(pubkey, privkey,
   1678 						       false)) {
   1679 					dst_key_setflags(privkey, flags);
   1680 				}
   1681 				dst_key_setflags(pubkey, flags);
   1682 			}
   1683 		}
   1684 
   1685 		if (result != ISC_R_SUCCESS) {
   1686 			char filename[DNS_NAME_FORMATSIZE +
   1687 				      DNS_SECALG_FORMATSIZE +
   1688 				      sizeof("key file for //65535")];
   1689 			isc_result_t result2;
   1690 			isc_buffer_t buf;
   1691 
   1692 			isc_buffer_init(&buf, filename, NAME_MAX);
   1693 			result2 = dst_key_getfilename(dst_key_name(pubkey),
   1694 						      dst_key_id(pubkey),
   1695 						      dst_key_alg(pubkey),
   1696 						      (DST_TYPE_PUBLIC |
   1697 						       DST_TYPE_PRIVATE),
   1698 						      directory, mctx,
   1699 						      &buf);
   1700 			if (result2 != ISC_R_SUCCESS) {
   1701 				char namebuf[DNS_NAME_FORMATSIZE];
   1702 				char algbuf[DNS_SECALG_FORMATSIZE];
   1703 
   1704 				dns_name_format(dst_key_name(pubkey),
   1705 						namebuf, sizeof(namebuf));
   1706 				dns_secalg_format(dst_key_alg(pubkey),
   1707 						  algbuf, sizeof(algbuf));
   1708 				snprintf(filename, sizeof(filename) - 1,
   1709 					 "key file for %s/%s/%d",
   1710 					 namebuf, algbuf, dst_key_id(pubkey));
   1711 			}
   1712 
   1713 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1714 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
   1715 				      "dns_dnssec_keylistfromrdataset: error "
   1716 				      "reading %s: %s",
   1717 				      filename, isc_result_totext(result));
   1718 		}
   1719 
   1720 		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
   1721 			RETERR(addkey(keylist, &pubkey, savekeys, mctx));
   1722 			goto skip;
   1723 		}
   1724 		RETERR(result);
   1725 
   1726 		/* This should never happen. */
   1727 		if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
   1728 			goto skip;
   1729 
   1730 		/*
   1731 		 * Whatever the key's default TTL may have
   1732 		 * been, the rdataset TTL takes priority.
   1733 		 */
   1734 		dst_key_setttl(privkey, dst_key_getttl(pubkey));
   1735 
   1736 		RETERR(addkey(keylist, &privkey, savekeys, mctx));
   1737  skip:
   1738 		if (pubkey != NULL)
   1739 			dst_key_free(&pubkey);
   1740 		if (privkey != NULL)
   1741 			dst_key_free(&privkey);
   1742 	}
   1743 
   1744 	if (result != ISC_R_NOMORE)
   1745 		RETERR(result);
   1746 
   1747 	if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
   1748 		RETERR(mark_active_keys(keylist, keysigs));
   1749 
   1750 	if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
   1751 		RETERR(mark_active_keys(keylist, soasigs));
   1752 
   1753 	result = ISC_R_SUCCESS;
   1754 
   1755  failure:
   1756 	if (dns_rdataset_isassociated(&keys))
   1757 		dns_rdataset_disassociate(&keys);
   1758 	if (pubkey != NULL)
   1759 		dst_key_free(&pubkey);
   1760 	if (privkey != NULL)
   1761 		dst_key_free(&privkey);
   1762 	return (result);
   1763 }
   1764 
   1765 static isc_result_t
   1766 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
   1767 	    dns_rdata_t *target)
   1768 {
   1769 	isc_result_t result;
   1770 	isc_buffer_t b;
   1771 	isc_region_t r;
   1772 
   1773 	isc_buffer_init(&b, buf, bufsize);
   1774 	result = dst_key_todns(key, &b);
   1775 	if (result != ISC_R_SUCCESS)
   1776 		return (result);
   1777 
   1778 	dns_rdata_reset(target);
   1779 	isc_buffer_usedregion(&b, &r);
   1780 	dns_rdata_fromregion(target, dst_key_class(key),
   1781 			     dns_rdatatype_dnskey, &r);
   1782 	return (ISC_R_SUCCESS);
   1783 }
   1784 
   1785 static isc_result_t
   1786 addrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
   1787 	dns_ttl_t ttl, isc_mem_t *mctx)
   1788 {
   1789 	isc_result_t result;
   1790 	dns_difftuple_t *tuple = NULL;
   1791 
   1792 	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
   1793 				    rdata, &tuple));
   1794 	dns_diff_appendminimal(diff, &tuple);
   1795 
   1796  failure:
   1797 	return (result);
   1798 }
   1799 
   1800 static isc_result_t
   1801 delrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
   1802 	 dns_ttl_t ttl, isc_mem_t *mctx)
   1803 {
   1804 	isc_result_t result;
   1805 	dns_difftuple_t *tuple = NULL;
   1806 
   1807 	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl,
   1808 				    rdata, &tuple));
   1809 	dns_diff_appendminimal(diff, &tuple);
   1810 
   1811  failure:
   1812 	return (result);
   1813 }
   1814 
   1815 static isc_result_t
   1816 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
   1817 	    dns_ttl_t ttl, isc_mem_t *mctx, bool allzsk,
   1818 	    void (*report)(const char *, ...))
   1819 {
   1820 	isc_result_t result;
   1821 	unsigned char buf[DST_KEY_MAXSIZE];
   1822 	char keystr[DST_KEY_FORMATSIZE];
   1823 	dns_rdata_t dnskey = DNS_RDATA_INIT;
   1824 
   1825 	dns_rdata_reset(&dnskey);
   1826 	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
   1827 	dst_key_format(key->key, keystr, sizeof(keystr));
   1828 
   1829 	report("Fetching %s (%s) from key %s.",
   1830 	       keystr, key->ksk ? (allzsk ? "KSK/ZSK" : "KSK") : "ZSK",
   1831 	       key->source == dns_keysource_user ?  "file" : "repository");
   1832 
   1833 	if (key->prepublish && ttl > key->prepublish) {
   1834 		isc_stdtime_t now;
   1835 
   1836 		report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
   1837 		       keystr, ttl);
   1838 
   1839 		isc_stdtime_get(&now);
   1840 		dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
   1841 	}
   1842 
   1843 	/* publish key */
   1844 	result = addrdata(&dnskey, diff, origin, ttl, mctx);
   1845 
   1846  failure:
   1847 	return (result);
   1848 }
   1849 
   1850 static isc_result_t
   1851 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
   1852 	  dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
   1853 	  void (*report)(const char *, ...))
   1854 {
   1855 	isc_result_t result;
   1856 	unsigned char buf[DST_KEY_MAXSIZE];
   1857 	dns_rdata_t dnskey = DNS_RDATA_INIT;
   1858 	char alg[80];
   1859 
   1860 	dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
   1861 	report("Removing %s key %d/%s from DNSKEY RRset.",
   1862 	       reason, dst_key_id(key->key), alg);
   1863 
   1864 	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
   1865 	result = delrdata(&dnskey, diff, origin, ttl, mctx);
   1866 
   1867  failure:
   1868 	return (result);
   1869 }
   1870 
   1871 static bool
   1872 exists(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
   1873 	isc_result_t result;
   1874 	dns_rdataset_t trdataset;
   1875 
   1876 	dns_rdataset_init(&trdataset);
   1877 	dns_rdataset_clone(rdataset, &trdataset);
   1878 	for (result = dns_rdataset_first(&trdataset);
   1879 	     result == ISC_R_SUCCESS;
   1880 	     result = dns_rdataset_next(&trdataset)) {
   1881 		dns_rdata_t current = DNS_RDATA_INIT;
   1882 
   1883 		dns_rdataset_current(&trdataset, &current);
   1884 		if (dns_rdata_compare(rdata, &current) == 0) {
   1885 			dns_rdataset_disassociate(&trdataset);
   1886 			return (true);
   1887 		}
   1888 	}
   1889 	dns_rdataset_disassociate(&trdataset);
   1890 	return (false);
   1891 }
   1892 
   1893 isc_result_t
   1894 dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys,
   1895 		      dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
   1896 		      isc_stdtime_t now, dns_ttl_t ttl, dns_diff_t *diff,
   1897 		      isc_mem_t *mctx)
   1898 {
   1899 	unsigned char dsbuf1[DNS_DS_BUFFERSIZE];
   1900 	unsigned char dsbuf2[DNS_DS_BUFFERSIZE];
   1901 	unsigned char keybuf[DST_KEY_MAXSIZE];
   1902 	isc_result_t result;
   1903 	dns_dnsseckey_t *key;
   1904 
   1905 	for (key = ISC_LIST_HEAD(*keys);
   1906 	     key != NULL;
   1907 	     key = ISC_LIST_NEXT(key, link)) {
   1908 		dns_rdata_t cdsrdata1 = DNS_RDATA_INIT;
   1909 		dns_rdata_t cdsrdata2 = DNS_RDATA_INIT;
   1910 		dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
   1911 		dns_name_t *origin = dst_key_name(key->key);
   1912 
   1913 		RETERR(make_dnskey(key->key, keybuf, sizeof(keybuf),
   1914 				   &cdnskeyrdata));
   1915 
   1916 		/*
   1917 		 * XXXMPA we need to be able to specify the DS algorithms
   1918 		 * to be used here and below with rmkeys.
   1919 		 */
   1920 		RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
   1921 					 DNS_DSDIGEST_SHA1, dsbuf1,
   1922 					 &cdsrdata1));
   1923 		RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
   1924 					 DNS_DSDIGEST_SHA256, dsbuf2,
   1925 					 &cdsrdata2));
   1926 
   1927 		/*
   1928 		 * Now that the we have created the DS records convert
   1929 		 * the rdata to CDNSKEY and CDS for comparison.
   1930 		 */
   1931 		cdnskeyrdata.type = dns_rdatatype_cdnskey;
   1932 		cdsrdata1.type = dns_rdatatype_cds;
   1933 		cdsrdata2.type = dns_rdatatype_cds;
   1934 
   1935 		if (syncpublish(key->key, now)) {
   1936 			if (!dns_rdataset_isassociated(cdnskey) ||
   1937 			    !exists(cdnskey, &cdnskeyrdata))
   1938 			{
   1939 				RETERR(addrdata(&cdnskeyrdata, diff, origin,
   1940 						ttl, mctx));
   1941 			}
   1942 			if (!dns_rdataset_isassociated(cds) ||
   1943 			    !exists(cds, &cdsrdata1))
   1944 			{
   1945 				RETERR(addrdata(&cdsrdata1, diff, origin,
   1946 						ttl, mctx));
   1947 			}
   1948 			if (!dns_rdataset_isassociated(cds) ||
   1949 			    !exists(cds, &cdsrdata2))
   1950 			{
   1951 				RETERR(addrdata(&cdsrdata2, diff, origin,
   1952 						ttl, mctx));
   1953 			}
   1954 		}
   1955 
   1956 		if (dns_rdataset_isassociated(cds) &&
   1957 		    syncdelete(key->key, now)) {
   1958 			if (exists(cds, &cdsrdata1))
   1959 				RETERR(delrdata(&cdsrdata1, diff, origin,
   1960 						cds->ttl, mctx));
   1961 			if (exists(cds, &cdsrdata2))
   1962 				RETERR(delrdata(&cdsrdata2, diff, origin,
   1963 						cds->ttl, mctx));
   1964 		}
   1965 
   1966 		if (dns_rdataset_isassociated(cdnskey) &&
   1967 		    syncdelete(key->key, now)) {
   1968 			if (exists(cdnskey, &cdnskeyrdata))
   1969 				RETERR(delrdata(&cdnskeyrdata, diff, origin,
   1970 						cdnskey->ttl, mctx));
   1971 		}
   1972 	}
   1973 
   1974 	if (!dns_rdataset_isassociated(cds) &&
   1975 	    !dns_rdataset_isassociated(cdnskey))
   1976 		return (ISC_R_SUCCESS);
   1977 
   1978 	/*
   1979 	 * Unconditionaly remove CDS/DNSKEY records for removed keys.
   1980 	 */
   1981 	for (key = ISC_LIST_HEAD(*rmkeys);
   1982 	     key != NULL;
   1983 	     key = ISC_LIST_NEXT(key, link)) {
   1984 		dns_rdata_t cdsrdata1 = DNS_RDATA_INIT;
   1985 		dns_rdata_t cdsrdata2 = DNS_RDATA_INIT;
   1986 		dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
   1987 		dns_name_t *origin = dst_key_name(key->key);
   1988 
   1989 		RETERR(make_dnskey(key->key, keybuf, sizeof(keybuf),
   1990 				   &cdnskeyrdata));
   1991 
   1992 		if (dns_rdataset_isassociated(cds)) {
   1993 			RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
   1994 						 DNS_DSDIGEST_SHA1, dsbuf1,
   1995 						 &cdsrdata1));
   1996 			RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
   1997 						 DNS_DSDIGEST_SHA256, dsbuf2,
   1998 						 &cdsrdata2));
   1999 			if (exists(cds, &cdsrdata1))
   2000 				RETERR(delrdata(&cdsrdata1, diff, origin,
   2001 						cds->ttl, mctx));
   2002 			if (exists(cds, &cdsrdata2))
   2003 				RETERR(delrdata(&cdsrdata2, diff, origin,
   2004 						cds->ttl, mctx));
   2005 		}
   2006 
   2007 		if (dns_rdataset_isassociated(cdnskey)) {
   2008 			if (exists(cdnskey, &cdnskeyrdata))
   2009 				RETERR(delrdata(&cdnskeyrdata, diff, origin,
   2010 						cdnskey->ttl, mctx));
   2011 		}
   2012 	}
   2013 
   2014 	result = ISC_R_SUCCESS;
   2015 
   2016  failure:
   2017 	return (result);
   2018 }
   2019 
   2020 /*
   2021  * Update 'keys' with information from 'newkeys'.
   2022  *
   2023  * If 'removed' is not NULL, any keys that are being removed from
   2024  * the zone will be added to the list for post-removal processing.
   2025  */
   2026 isc_result_t
   2027 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
   2028 		      dns_dnsseckeylist_t *removed, const dns_name_t *origin,
   2029 		      dns_ttl_t hint_ttl, dns_diff_t *diff,
   2030 		      bool allzsk, isc_mem_t *mctx,
   2031 		      void (*report)(const char *, ...))
   2032 {
   2033 	isc_result_t result;
   2034 	dns_dnsseckey_t *key, *key1, *key2, *next;
   2035 	bool found_ttl = false;
   2036 	dns_ttl_t ttl = hint_ttl;
   2037 
   2038 	/*
   2039 	 * First, look through the existing key list to find keys
   2040 	 * supplied from the command line which are not in the zone.
   2041 	 * Update the zone to include them.
   2042 	 *
   2043 	 * Also, if there are keys published in the zone already,
   2044 	 * use their TTL for all subsequent published keys.
   2045 	 */
   2046 	for (key = ISC_LIST_HEAD(*keys);
   2047 	     key != NULL;
   2048 	     key = ISC_LIST_NEXT(key, link))
   2049 	{
   2050 		if (key->source == dns_keysource_user &&
   2051 		    (key->hint_publish || key->force_publish))
   2052 		{
   2053 			RETERR(publish_key(diff, key, origin, ttl,
   2054 					   mctx, allzsk, report));
   2055 		}
   2056 		if (key->source == dns_keysource_zoneapex) {
   2057 			ttl = dst_key_getttl(key->key);
   2058 			found_ttl = true;
   2059 		}
   2060 	}
   2061 
   2062 	/*
   2063 	 * If there were no existing keys, use the smallest nonzero
   2064 	 * TTL of the keys found in the repository.
   2065 	 */
   2066 	if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
   2067 		dns_ttl_t shortest = 0;
   2068 
   2069 		for (key = ISC_LIST_HEAD(*newkeys);
   2070 		     key != NULL;
   2071 		     key = ISC_LIST_NEXT(key, link))
   2072 		{
   2073 			dns_ttl_t thisttl = dst_key_getttl(key->key);
   2074 			if (thisttl != 0 &&
   2075 			    (shortest == 0 || thisttl < shortest))
   2076 			{
   2077 				shortest = thisttl;
   2078 			}
   2079 		}
   2080 
   2081 		if (shortest != 0) {
   2082 			ttl = shortest;
   2083 		}
   2084 	}
   2085 
   2086 	/*
   2087 	 * Second, scan the list of newly found keys looking for matches
   2088 	 * with known keys, and update accordingly.
   2089 	 */
   2090 	for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
   2091 		bool key_revoked = false;
   2092 		char keystr1[DST_KEY_FORMATSIZE];
   2093 		char keystr2[DST_KEY_FORMATSIZE];
   2094 
   2095 		next = ISC_LIST_NEXT(key1, link);
   2096 
   2097 		for (key2 = ISC_LIST_HEAD(*keys);
   2098 		     key2 != NULL;
   2099 		     key2 = ISC_LIST_NEXT(key2, link))
   2100 		{
   2101 			int f1 = dst_key_flags(key1->key);
   2102 			int f2 = dst_key_flags(key2->key);
   2103 			int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
   2104 			int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
   2105 			if (nr1 == nr2 &&
   2106 			    dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
   2107 			    dst_key_pubcompare(key1->key, key2->key, true))
   2108 			{
   2109 				int r1, r2;
   2110 				r1 = dst_key_flags(key1->key) &
   2111 					DNS_KEYFLAG_REVOKE;
   2112 				r2 = dst_key_flags(key2->key) &
   2113 					DNS_KEYFLAG_REVOKE;
   2114 				key_revoked = (r1 != r2);
   2115 				break;
   2116 			}
   2117 		}
   2118 
   2119 		/* Printable version of key1 (the newly aquired key) */
   2120 		dst_key_format(key1->key, keystr1, sizeof(keystr1));
   2121 
   2122 		/* No match found in keys; add the new key. */
   2123 		if (key2 == NULL) {
   2124 			ISC_LIST_UNLINK(*newkeys, key1, link);
   2125 			ISC_LIST_APPEND(*keys, key1, link);
   2126 
   2127 			if (key1->source != dns_keysource_zoneapex &&
   2128 			    (key1->hint_publish || key1->force_publish))
   2129 			{
   2130 				RETERR(publish_key(diff, key1, origin, ttl,
   2131 						   mctx, allzsk, report));
   2132 				isc_log_write(dns_lctx,
   2133 					      DNS_LOGCATEGORY_DNSSEC,
   2134 					      DNS_LOGMODULE_DNSSEC,
   2135 					      ISC_LOG_INFO,
   2136 					      "DNSKEY %s (%s) is now published",
   2137 					      keystr1, key1->ksk ?
   2138 					      (allzsk ? "KSK/ZSK" : "KSK") :
   2139 					      "ZSK");
   2140 				if (key1->hint_sign || key1->force_sign) {
   2141 					key1->first_sign = true;
   2142 					isc_log_write(dns_lctx,
   2143 						      DNS_LOGCATEGORY_DNSSEC,
   2144 						      DNS_LOGMODULE_DNSSEC,
   2145 						      ISC_LOG_INFO,
   2146 						      "DNSKEY %s (%s) is now "
   2147 						      "active",
   2148 						      keystr1, key1->ksk ?
   2149 						      (allzsk ? "KSK/ZSK" :
   2150 						       "KSK") : "ZSK");
   2151 				}
   2152 			}
   2153 
   2154 			continue;
   2155 		}
   2156 
   2157 		/* Printable version of key2 (the old key, if any) */
   2158 		dst_key_format(key2->key, keystr2, sizeof(keystr2));
   2159 
   2160 		/* Match found: remove or update it as needed */
   2161 		if (key1->hint_remove) {
   2162 			RETERR(remove_key(diff, key2, origin, ttl, mctx,
   2163 					  "expired", report));
   2164 			ISC_LIST_UNLINK(*keys, key2, link);
   2165 
   2166 			if (removed != NULL) {
   2167 				ISC_LIST_APPEND(*removed, key2, link);
   2168 				isc_log_write(dns_lctx,
   2169 					      DNS_LOGCATEGORY_DNSSEC,
   2170 					      DNS_LOGMODULE_DNSSEC,
   2171 					      ISC_LOG_INFO,
   2172 					      "DNSKEY %s (%s) is now deleted",
   2173 					      keystr2, key2->ksk ? (allzsk ?
   2174 					      "KSK/ZSK" : "KSK") : "ZSK");
   2175 			} else {
   2176 				dns_dnsseckey_destroy(mctx, &key2);
   2177 			}
   2178 		} else if (key_revoked &&
   2179 			   (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0)
   2180 		{
   2181 
   2182 			/*
   2183 			 * A previously valid key has been revoked.
   2184 			 * We need to remove the old version and pull
   2185 			 * in the new one.
   2186 			 */
   2187 			RETERR(remove_key(diff, key2, origin, ttl, mctx,
   2188 					  "revoked", report));
   2189 			ISC_LIST_UNLINK(*keys, key2, link);
   2190 			if (removed != NULL) {
   2191 				ISC_LIST_APPEND(*removed, key2, link);
   2192 				isc_log_write(dns_lctx,
   2193 					      DNS_LOGCATEGORY_DNSSEC,
   2194 					      DNS_LOGMODULE_DNSSEC,
   2195 					      ISC_LOG_INFO,
   2196 					      "DNSKEY %s (%s) is now revoked; "
   2197 					      "new ID is %05d",
   2198 					      keystr2, key2->ksk ? (allzsk ?
   2199 					      "KSK/ZSK" : "KSK") : "ZSK",
   2200 					      dst_key_id(key1->key));
   2201 			} else {
   2202 				dns_dnsseckey_destroy(mctx, &key2);
   2203 			}
   2204 
   2205 			RETERR(publish_key(diff, key1, origin, ttl,
   2206 					   mctx, allzsk, report));
   2207 			ISC_LIST_UNLINK(*newkeys, key1, link);
   2208 			ISC_LIST_APPEND(*keys, key1, link);
   2209 
   2210 			/*
   2211 			 * XXX: The revoke flag is only defined for trust
   2212 			 * anchors.  Setting the flag on a non-KSK is legal,
   2213 			 * but not defined in any RFC.  It seems reasonable
   2214 			 * to treat it the same as a KSK: keep it in the
   2215 			 * zone, sign the DNSKEY set with it, but not
   2216 			 * sign other records with it.
   2217 			 */
   2218 			key1->ksk = true;
   2219 			continue;
   2220 		} else {
   2221 			if (!key2->is_active &&
   2222 			    (key1->hint_sign || key1->force_sign))
   2223 			{
   2224 				key2->first_sign = true;
   2225 				isc_log_write(dns_lctx,
   2226 					      DNS_LOGCATEGORY_DNSSEC,
   2227 					      DNS_LOGMODULE_DNSSEC,
   2228 					      ISC_LOG_INFO,
   2229 					      "DNSKEY %s (%s) is now active",
   2230 					      keystr1, key1->ksk ? (allzsk ?
   2231 					      "KSK/ZSK" : "KSK") : "ZSK");
   2232 			} else if (key2->is_active &&
   2233 				   !key1->hint_sign && !key1->force_sign)
   2234 			{
   2235 				isc_log_write(dns_lctx,
   2236 					      DNS_LOGCATEGORY_DNSSEC,
   2237 					      DNS_LOGMODULE_DNSSEC,
   2238 					      ISC_LOG_INFO,
   2239 					      "DNSKEY %s (%s) is now inactive",
   2240 					      keystr1, key1->ksk ? (allzsk ?
   2241 					      "KSK/ZSK" : "KSK") : "ZSK");
   2242 			}
   2243 
   2244 			key2->hint_sign = key1->hint_sign;
   2245 			key2->hint_publish = key1->hint_publish;
   2246 		}
   2247 	}
   2248 
   2249 	/* Free any leftover keys in newkeys */
   2250 	while (!ISC_LIST_EMPTY(*newkeys)) {
   2251 		key1 = ISC_LIST_HEAD(*newkeys);
   2252 		ISC_LIST_UNLINK(*newkeys, key1, link);
   2253 		dns_dnsseckey_destroy(mctx, &key1);
   2254 	}
   2255 
   2256 	result = ISC_R_SUCCESS;
   2257 
   2258  failure:
   2259 	return (result);
   2260 }
   2261