PageRenderTime 106ms CodeModel.GetById 15ms app.highlight 79ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/bind9/lib/dns/dnssec.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1768 lines | 1281 code | 258 blank | 229 comment | 400 complexity | 30a08016b58babe76cd80e174ff1c03f MD5 | raw file
   1/*
   2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
   3 * Copyright (C) 1999-2003  Internet Software Consortium.
   4 *
   5 * Permission to use, copy, modify, and/or distribute this software for any
   6 * purpose with or without fee is hereby granted, provided that the above
   7 * copyright notice and this permission notice appear in all copies.
   8 *
   9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15 * PERFORMANCE OF THIS SOFTWARE.
  16 */
  17
  18/*
  19 * $Id$
  20 */
  21
  22/*! \file */
  23
  24#include <config.h>
  25
  26#include <stdlib.h>
  27
  28#include <isc/buffer.h>
  29#include <isc/dir.h>
  30#include <isc/mem.h>
  31#include <isc/serial.h>
  32#include <isc/string.h>
  33#include <isc/util.h>
  34
  35#include <dns/db.h>
  36#include <dns/diff.h>
  37#include <dns/dnssec.h>
  38#include <dns/fixedname.h>
  39#include <dns/keyvalues.h>
  40#include <dns/log.h>
  41#include <dns/message.h>
  42#include <dns/rdata.h>
  43#include <dns/rdatalist.h>
  44#include <dns/rdataset.h>
  45#include <dns/rdatastruct.h>
  46#include <dns/result.h>
  47#include <dns/tsig.h>		/* for DNS_TSIG_FUDGE */
  48
  49#include <dst/result.h>
  50
  51#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
  52
  53#define RETERR(x) do { \
  54	result = (x); \
  55	if (result != ISC_R_SUCCESS) \
  56		goto failure; \
  57	} while (0)
  58
  59
  60#define TYPE_SIGN 0
  61#define TYPE_VERIFY 1
  62
  63static isc_result_t
  64digest_callback(void *arg, isc_region_t *data);
  65
  66static int
  67rdata_compare_wrapper(const void *rdata1, const void *rdata2);
  68
  69static isc_result_t
  70rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
  71			dns_rdata_t **rdata, int *nrdata);
  72
  73static isc_result_t
  74digest_callback(void *arg, isc_region_t *data) {
  75	dst_context_t *ctx = arg;
  76
  77	return (dst_context_adddata(ctx, data));
  78}
  79
  80/*
  81 * Make qsort happy.
  82 */
  83static int
  84rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
  85	return (dns_rdata_compare((const dns_rdata_t *)rdata1,
  86				  (const dns_rdata_t *)rdata2));
  87}
  88
  89/*
  90 * Sort the rdataset into an array.
  91 */
  92static isc_result_t
  93rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
  94			dns_rdata_t **rdata, int *nrdata)
  95{
  96	isc_result_t ret;
  97	int i = 0, n;
  98	dns_rdata_t *data;
  99	dns_rdataset_t rdataset;
 100
 101	n = dns_rdataset_count(set);
 102
 103	data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
 104	if (data == NULL)
 105		return (ISC_R_NOMEMORY);
 106
 107	dns_rdataset_init(&rdataset);
 108	dns_rdataset_clone(set, &rdataset);
 109	ret = dns_rdataset_first(&rdataset);
 110	if (ret != ISC_R_SUCCESS) {
 111		dns_rdataset_disassociate(&rdataset);
 112		isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
 113		return (ret);
 114	}
 115
 116	/*
 117	 * Put them in the array.
 118	 */
 119	do {
 120		dns_rdata_init(&data[i]);
 121		dns_rdataset_current(&rdataset, &data[i++]);
 122	} while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
 123
 124	/*
 125	 * Sort the array.
 126	 */
 127	qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
 128	*rdata = data;
 129	*nrdata = n;
 130	dns_rdataset_disassociate(&rdataset);
 131	return (ISC_R_SUCCESS);
 132}
 133
 134isc_result_t
 135dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
 136			dst_key_t **key)
 137{
 138	isc_buffer_t b;
 139	isc_region_t r;
 140
 141	INSIST(name != NULL);
 142	INSIST(rdata != NULL);
 143	INSIST(mctx != NULL);
 144	INSIST(key != NULL);
 145	INSIST(*key == NULL);
 146	REQUIRE(rdata->type == dns_rdatatype_key ||
 147		rdata->type == dns_rdatatype_dnskey);
 148
 149	dns_rdata_toregion(rdata, &r);
 150	isc_buffer_init(&b, r.base, r.length);
 151	isc_buffer_add(&b, r.length);
 152	return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
 153}
 154
 155static isc_result_t
 156digest_sig(dst_context_t *ctx, dns_rdata_t *sigrdata, dns_rdata_rrsig_t *sig) {
 157	isc_region_t r;
 158	isc_result_t ret;
 159	dns_fixedname_t fname;
 160
 161	dns_rdata_toregion(sigrdata, &r);
 162	INSIST(r.length >= 19);
 163
 164	r.length = 18;
 165	ret = dst_context_adddata(ctx, &r);
 166	if (ret != ISC_R_SUCCESS)
 167		return (ret);
 168	dns_fixedname_init(&fname);
 169	RUNTIME_CHECK(dns_name_downcase(&sig->signer,
 170					dns_fixedname_name(&fname), NULL)
 171		      == ISC_R_SUCCESS);
 172	dns_name_toregion(dns_fixedname_name(&fname), &r);
 173	return (dst_context_adddata(ctx, &r));
 174}
 175
 176isc_result_t
 177dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
 178		isc_stdtime_t *inception, isc_stdtime_t *expire,
 179		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
 180{
 181	dns_rdata_rrsig_t sig;
 182	dns_rdata_t tmpsigrdata;
 183	dns_rdata_t *rdatas;
 184	int nrdatas, i;
 185	isc_buffer_t sigbuf, envbuf;
 186	isc_region_t r;
 187	dst_context_t *ctx = NULL;
 188	isc_result_t ret;
 189	isc_buffer_t *databuf = NULL;
 190	char data[256 + 8];
 191	isc_uint32_t flags;
 192	unsigned int sigsize;
 193	dns_fixedname_t fnewname;
 194
 195	REQUIRE(name != NULL);
 196	REQUIRE(dns_name_countlabels(name) <= 255);
 197	REQUIRE(set != NULL);
 198	REQUIRE(key != NULL);
 199	REQUIRE(inception != NULL);
 200	REQUIRE(expire != NULL);
 201	REQUIRE(mctx != NULL);
 202	REQUIRE(sigrdata != NULL);
 203
 204	if (*inception >= *expire)
 205		return (DNS_R_INVALIDTIME);
 206
 207	/*
 208	 * Is the key allowed to sign data?
 209	 */
 210	flags = dst_key_flags(key);
 211	if (flags & DNS_KEYTYPE_NOAUTH)
 212		return (DNS_R_KEYUNAUTHORIZED);
 213	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
 214		return (DNS_R_KEYUNAUTHORIZED);
 215
 216	sig.mctx = mctx;
 217	sig.common.rdclass = set->rdclass;
 218	sig.common.rdtype = dns_rdatatype_rrsig;
 219	ISC_LINK_INIT(&sig.common, link);
 220
 221	dns_name_init(&sig.signer, NULL);
 222	dns_name_clone(dst_key_name(key), &sig.signer);
 223
 224	sig.covered = set->type;
 225	sig.algorithm = dst_key_alg(key);
 226	sig.labels = dns_name_countlabels(name) - 1;
 227	if (dns_name_iswildcard(name))
 228		sig.labels--;
 229	sig.originalttl = set->ttl;
 230	sig.timesigned = *inception;
 231	sig.timeexpire = *expire;
 232	sig.keyid = dst_key_id(key);
 233	ret = dst_key_sigsize(key, &sigsize);
 234	if (ret != ISC_R_SUCCESS)
 235		return (ret);
 236	sig.siglen = sigsize;
 237	/*
 238	 * The actual contents of sig.signature are not important yet, since
 239	 * they're not used in digest_sig().
 240	 */
 241	sig.signature = isc_mem_get(mctx, sig.siglen);
 242	if (sig.signature == NULL)
 243		return (ISC_R_NOMEMORY);
 244
 245	ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
 246	if (ret != ISC_R_SUCCESS)
 247		goto cleanup_signature;
 248
 249	dns_rdata_init(&tmpsigrdata);
 250	ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
 251				   sig.common.rdtype, &sig, databuf);
 252	if (ret != ISC_R_SUCCESS)
 253		goto cleanup_databuf;
 254
 255	ret = dst_context_create(key, mctx, &ctx);
 256	if (ret != ISC_R_SUCCESS)
 257		goto cleanup_databuf;
 258
 259	/*
 260	 * Digest the SIG rdata.
 261	 */
 262	ret = digest_sig(ctx, &tmpsigrdata, &sig);
 263	if (ret != ISC_R_SUCCESS)
 264		goto cleanup_context;
 265
 266	dns_fixedname_init(&fnewname);
 267	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
 268					NULL) == ISC_R_SUCCESS);
 269	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
 270
 271	/*
 272	 * Create an envelope for each rdata: <name|type|class|ttl>.
 273	 */
 274	isc_buffer_init(&envbuf, data, sizeof(data));
 275	memcpy(data, r.base, r.length);
 276	isc_buffer_add(&envbuf, r.length);
 277	isc_buffer_putuint16(&envbuf, set->type);
 278	isc_buffer_putuint16(&envbuf, set->rdclass);
 279	isc_buffer_putuint32(&envbuf, set->ttl);
 280
 281	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
 282	if (ret != ISC_R_SUCCESS)
 283		goto cleanup_context;
 284	isc_buffer_usedregion(&envbuf, &r);
 285
 286	for (i = 0; i < nrdatas; i++) {
 287		isc_uint16_t len;
 288		isc_buffer_t lenbuf;
 289		isc_region_t lenr;
 290
 291		/*
 292		 * Skip duplicates.
 293		 */
 294		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
 295		    continue;
 296
 297		/*
 298		 * Digest the envelope.
 299		 */
 300		ret = dst_context_adddata(ctx, &r);
 301		if (ret != ISC_R_SUCCESS)
 302			goto cleanup_array;
 303
 304		/*
 305		 * Digest the length of the rdata.
 306		 */
 307		isc_buffer_init(&lenbuf, &len, sizeof(len));
 308		INSIST(rdatas[i].length < 65536);
 309		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
 310		isc_buffer_usedregion(&lenbuf, &lenr);
 311		ret = dst_context_adddata(ctx, &lenr);
 312		if (ret != ISC_R_SUCCESS)
 313			goto cleanup_array;
 314
 315		/*
 316		 * Digest the rdata.
 317		 */
 318		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
 319		if (ret != ISC_R_SUCCESS)
 320			goto cleanup_array;
 321	}
 322
 323	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
 324	ret = dst_context_sign(ctx, &sigbuf);
 325	if (ret != ISC_R_SUCCESS)
 326		goto cleanup_array;
 327	isc_buffer_usedregion(&sigbuf, &r);
 328	if (r.length != sig.siglen) {
 329		ret = ISC_R_NOSPACE;
 330		goto cleanup_array;
 331	}
 332	memcpy(sig.signature, r.base, sig.siglen);
 333
 334	ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
 335				  sig.common.rdtype, &sig, buffer);
 336
 337cleanup_array:
 338	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
 339cleanup_context:
 340	dst_context_destroy(&ctx);
 341cleanup_databuf:
 342	isc_buffer_free(&databuf);
 343cleanup_signature:
 344	isc_mem_put(mctx, sig.signature, sig.siglen);
 345
 346	return (ret);
 347}
 348
 349isc_result_t
 350dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
 351		   isc_boolean_t ignoretime, isc_mem_t *mctx,
 352		   dns_rdata_t *sigrdata, dns_name_t *wild)
 353{
 354	dns_rdata_rrsig_t sig;
 355	dns_fixedname_t fnewname;
 356	isc_region_t r;
 357	isc_buffer_t envbuf;
 358	dns_rdata_t *rdatas;
 359	int nrdatas, i;
 360	isc_stdtime_t now;
 361	isc_result_t ret;
 362	unsigned char data[300];
 363	dst_context_t *ctx = NULL;
 364	int labels = 0;
 365	isc_uint32_t flags;
 366
 367	REQUIRE(name != NULL);
 368	REQUIRE(set != NULL);
 369	REQUIRE(key != NULL);
 370	REQUIRE(mctx != NULL);
 371	REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
 372
 373	ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
 374	if (ret != ISC_R_SUCCESS)
 375		return (ret);
 376
 377	if (set->type != sig.covered)
 378		return (DNS_R_SIGINVALID);
 379
 380	if (isc_serial_lt(sig.timeexpire, sig.timesigned))
 381		return (DNS_R_SIGINVALID);
 382
 383	if (!ignoretime) {
 384		isc_stdtime_get(&now);
 385
 386		/*
 387		 * Is SIG temporally valid?
 388		 */
 389		if (isc_serial_lt((isc_uint32_t)now, sig.timesigned))
 390			return (DNS_R_SIGFUTURE);
 391		else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now))
 392			return (DNS_R_SIGEXPIRED);
 393	}
 394
 395	/*
 396	 * NS, SOA and DNSSKEY records are signed by their owner.
 397	 * DS records are signed by the parent.
 398	 */
 399	switch (set->type) {
 400	case dns_rdatatype_ns:
 401	case dns_rdatatype_soa:
 402	case dns_rdatatype_dnskey:
 403		if (!dns_name_equal(name, &sig.signer))
 404			return (DNS_R_SIGINVALID);
 405		break;
 406	case dns_rdatatype_ds:
 407		if (dns_name_equal(name, &sig.signer))
 408			return (DNS_R_SIGINVALID);
 409		/* FALLTHROUGH */
 410	default:
 411		if (!dns_name_issubdomain(name, &sig.signer))
 412			return (DNS_R_SIGINVALID);
 413		break;
 414	}
 415
 416	/*
 417	 * Is the key allowed to sign data?
 418	 */
 419	flags = dst_key_flags(key);
 420	if (flags & DNS_KEYTYPE_NOAUTH)
 421		return (DNS_R_KEYUNAUTHORIZED);
 422	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
 423		return (DNS_R_KEYUNAUTHORIZED);
 424
 425	ret = dst_context_create(key, mctx, &ctx);
 426	if (ret != ISC_R_SUCCESS)
 427		goto cleanup_struct;
 428
 429	/*
 430	 * Digest the SIG rdata (not including the signature).
 431	 */
 432	ret = digest_sig(ctx, sigrdata, &sig);
 433	if (ret != ISC_R_SUCCESS)
 434		goto cleanup_context;
 435
 436	/*
 437	 * If the name is an expanded wildcard, use the wildcard name.
 438	 */
 439	dns_fixedname_init(&fnewname);
 440	labels = dns_name_countlabels(name) - 1;
 441	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
 442					NULL) == ISC_R_SUCCESS);
 443	if (labels - sig.labels > 0)
 444		dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
 445			       NULL, dns_fixedname_name(&fnewname));
 446
 447	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
 448
 449	/*
 450	 * Create an envelope for each rdata: <name|type|class|ttl>.
 451	 */
 452	isc_buffer_init(&envbuf, data, sizeof(data));
 453	if (labels - sig.labels > 0) {
 454		isc_buffer_putuint8(&envbuf, 1);
 455		isc_buffer_putuint8(&envbuf, '*');
 456		memcpy(data + 2, r.base, r.length);
 457	}
 458	else
 459		memcpy(data, r.base, r.length);
 460	isc_buffer_add(&envbuf, r.length);
 461	isc_buffer_putuint16(&envbuf, set->type);
 462	isc_buffer_putuint16(&envbuf, set->rdclass);
 463	isc_buffer_putuint32(&envbuf, sig.originalttl);
 464
 465	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
 466	if (ret != ISC_R_SUCCESS)
 467		goto cleanup_context;
 468
 469	isc_buffer_usedregion(&envbuf, &r);
 470
 471	for (i = 0; i < nrdatas; i++) {
 472		isc_uint16_t len;
 473		isc_buffer_t lenbuf;
 474		isc_region_t lenr;
 475
 476		/*
 477		 * Skip duplicates.
 478		 */
 479		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
 480		    continue;
 481
 482		/*
 483		 * Digest the envelope.
 484		 */
 485		ret = dst_context_adddata(ctx, &r);
 486		if (ret != ISC_R_SUCCESS)
 487			goto cleanup_array;
 488
 489		/*
 490		 * Digest the rdata length.
 491		 */
 492		isc_buffer_init(&lenbuf, &len, sizeof(len));
 493		INSIST(rdatas[i].length < 65536);
 494		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
 495		isc_buffer_usedregion(&lenbuf, &lenr);
 496
 497		/*
 498		 * Digest the rdata.
 499		 */
 500		ret = dst_context_adddata(ctx, &lenr);
 501		if (ret != ISC_R_SUCCESS)
 502			goto cleanup_array;
 503		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
 504		if (ret != ISC_R_SUCCESS)
 505			goto cleanup_array;
 506	}
 507
 508	r.base = sig.signature;
 509	r.length = sig.siglen;
 510	ret = dst_context_verify(ctx, &r);
 511	if (ret == DST_R_VERIFYFAILURE)
 512		ret = DNS_R_SIGINVALID;
 513
 514cleanup_array:
 515	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
 516cleanup_context:
 517	dst_context_destroy(&ctx);
 518cleanup_struct:
 519	dns_rdata_freestruct(&sig);
 520
 521	if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
 522		if (wild != NULL)
 523			RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
 524						 dns_fixedname_name(&fnewname),
 525						 wild, NULL) == ISC_R_SUCCESS);
 526		ret = DNS_R_FROMWILDCARD;
 527	}
 528	return (ret);
 529}
 530
 531isc_result_t
 532dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
 533		  isc_boolean_t ignoretime, isc_mem_t *mctx,
 534		  dns_rdata_t *sigrdata)
 535{
 536	isc_result_t result;
 537
 538	result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
 539				    sigrdata, NULL);
 540	if (result == DNS_R_FROMWILDCARD)
 541		result = ISC_R_SUCCESS;
 542	return (result);
 543}
 544
 545static isc_boolean_t
 546key_active(dst_key_t *key, isc_stdtime_t now) {
 547	isc_result_t result;
 548	isc_stdtime_t publish, active, revoke, inactive, delete;
 549	isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
 550	isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
 551	isc_boolean_t delset = ISC_FALSE;
 552	int major, minor;
 553
 554	/* Is this an old-style key? */
 555	result = dst_key_getprivateformat(key, &major, &minor);
 556	RUNTIME_CHECK(result == ISC_R_SUCCESS);
 557
 558	/*
 559	 * Smart signing started with key format 1.3; prior to that, all
 560	 * keys are assumed active
 561	 */
 562	if (major == 1 && minor <= 2)
 563		return (ISC_TRUE);
 564
 565	result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
 566	if (result == ISC_R_SUCCESS)
 567		pubset = ISC_TRUE;
 568
 569	result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
 570	if (result == ISC_R_SUCCESS)
 571		actset = ISC_TRUE;
 572
 573	result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
 574	if (result == ISC_R_SUCCESS)
 575		revset = ISC_TRUE;
 576
 577	result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
 578	if (result == ISC_R_SUCCESS)
 579		inactset = ISC_TRUE;
 580
 581	result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
 582	if (result == ISC_R_SUCCESS)
 583		delset = ISC_TRUE;
 584
 585	if ((inactset && inactive <= now) || (delset && delete <= now))
 586		return (ISC_FALSE);
 587
 588	if (revset && revoke <= now && pubset && publish <= now)
 589		return (ISC_TRUE);
 590
 591	if (actset && active <= now)
 592		return (ISC_TRUE);
 593
 594	return (ISC_FALSE);
 595}
 596
 597#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
 598			  == DNS_KEYOWNER_ZONE)
 599
 600isc_result_t
 601dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
 602			 dns_dbnode_t *node, dns_name_t *name,
 603			 const char *directory, isc_mem_t *mctx,
 604			 unsigned int maxkeys, dst_key_t **keys,
 605			 unsigned int *nkeys)
 606{
 607	dns_rdataset_t rdataset;
 608	dns_rdata_t rdata = DNS_RDATA_INIT;
 609	isc_result_t result;
 610	dst_key_t *pubkey = NULL;
 611	unsigned int count = 0;
 612	isc_stdtime_t now;
 613
 614	REQUIRE(nkeys != NULL);
 615	REQUIRE(keys != NULL);
 616
 617	isc_stdtime_get(&now);
 618
 619	*nkeys = 0;
 620	dns_rdataset_init(&rdataset);
 621	RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
 622				   &rdataset, NULL));
 623	RETERR(dns_rdataset_first(&rdataset));
 624	while (result == ISC_R_SUCCESS && count < maxkeys) {
 625		pubkey = NULL;
 626		dns_rdataset_current(&rdataset, &rdata);
 627		RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
 628		if (!is_zone_key(pubkey) ||
 629		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
 630			goto next;
 631		/* Corrupted .key file? */
 632		if (!dns_name_equal(name, dst_key_name(pubkey)))
 633			goto next;
 634		keys[count] = NULL;
 635		result = dst_key_fromfile(dst_key_name(pubkey),
 636					  dst_key_id(pubkey),
 637					  dst_key_alg(pubkey),
 638					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
 639					  directory,
 640					  mctx, &keys[count]);
 641
 642		/*
 643		 * If the key was revoked and the private file
 644		 * doesn't exist, maybe it was revoked internally
 645		 * by named.  Try loading the unrevoked version.
 646		 */
 647		if (result == ISC_R_FILENOTFOUND) {
 648			isc_uint32_t flags;
 649			flags = dst_key_flags(pubkey);
 650			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
 651				dst_key_setflags(pubkey,
 652						 flags & ~DNS_KEYFLAG_REVOKE);
 653				result = dst_key_fromfile(dst_key_name(pubkey),
 654							  dst_key_id(pubkey),
 655							  dst_key_alg(pubkey),
 656							  DST_TYPE_PUBLIC|
 657							  DST_TYPE_PRIVATE,
 658							  directory,
 659							  mctx, &keys[count]);
 660				if (result == ISC_R_SUCCESS &&
 661				    dst_key_pubcompare(pubkey, keys[count],
 662						       ISC_FALSE)) {
 663					dst_key_setflags(keys[count], flags);
 664				}
 665				dst_key_setflags(pubkey, flags);
 666			}
 667		}
 668
 669		if (result != ISC_R_SUCCESS) {
 670			char keybuf[DNS_NAME_FORMATSIZE];
 671			char algbuf[DNS_SECALG_FORMATSIZE];
 672			dns_name_format(dst_key_name(pubkey), keybuf,
 673					sizeof(keybuf));
 674			dns_secalg_format(dst_key_alg(pubkey), algbuf,
 675					  sizeof(algbuf));
 676			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
 677				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
 678				      "dns_dnssec_findzonekeys2: error "
 679				      "reading private key file %s/%s/%d: %s",
 680				      keybuf, algbuf, dst_key_id(pubkey),
 681				      isc_result_totext(result));
 682		}
 683
 684		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
 685			keys[count] = pubkey;
 686			pubkey = NULL;
 687			count++;
 688			goto next;
 689		}
 690
 691		if (result != ISC_R_SUCCESS)
 692			goto failure;
 693
 694		/*
 695		 * If a key is marked inactive, skip it
 696		 */
 697		if (!key_active(keys[count], now)) {
 698			dst_key_free(&keys[count]);
 699			keys[count] = pubkey;
 700			pubkey = NULL;
 701			count++;
 702			goto next;
 703		}
 704
 705		if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
 706			/* We should never get here. */
 707			dst_key_free(&keys[count]);
 708			goto next;
 709		}
 710		count++;
 711 next:
 712		if (pubkey != NULL)
 713			dst_key_free(&pubkey);
 714		dns_rdata_reset(&rdata);
 715		result = dns_rdataset_next(&rdataset);
 716	}
 717	if (result != ISC_R_NOMORE)
 718		goto failure;
 719	if (count == 0)
 720		result = ISC_R_NOTFOUND;
 721	else
 722		result = ISC_R_SUCCESS;
 723
 724 failure:
 725	if (dns_rdataset_isassociated(&rdataset))
 726		dns_rdataset_disassociate(&rdataset);
 727	if (pubkey != NULL)
 728		dst_key_free(&pubkey);
 729	if (result != ISC_R_SUCCESS)
 730		while (count > 0)
 731			dst_key_free(&keys[--count]);
 732	*nkeys = count;
 733	return (result);
 734}
 735
 736isc_result_t
 737dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
 738			dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
 739			unsigned int maxkeys, dst_key_t **keys,
 740			unsigned int *nkeys)
 741{
 742	return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
 743					 maxkeys, keys, nkeys));
 744}
 745
 746isc_result_t
 747dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
 748	dns_rdata_sig_t sig;	/* SIG(0) */
 749	unsigned char data[512];
 750	unsigned char header[DNS_MESSAGE_HEADERLEN];
 751	isc_buffer_t headerbuf, databuf, sigbuf;
 752	unsigned int sigsize;
 753	isc_buffer_t *dynbuf = NULL;
 754	dns_rdata_t *rdata;
 755	dns_rdatalist_t *datalist;
 756	dns_rdataset_t *dataset;
 757	isc_region_t r;
 758	isc_stdtime_t now;
 759	dst_context_t *ctx = NULL;
 760	isc_mem_t *mctx;
 761	isc_result_t result;
 762	isc_boolean_t signeedsfree = ISC_TRUE;
 763
 764	REQUIRE(msg != NULL);
 765	REQUIRE(key != NULL);
 766
 767	if (is_response(msg))
 768		REQUIRE(msg->query.base != NULL);
 769
 770	mctx = msg->mctx;
 771
 772	memset(&sig, 0, sizeof(sig));
 773
 774	sig.mctx = mctx;
 775	sig.common.rdclass = dns_rdataclass_any;
 776	sig.common.rdtype = dns_rdatatype_sig;	/* SIG(0) */
 777	ISC_LINK_INIT(&sig.common, link);
 778
 779	sig.covered = 0;
 780	sig.algorithm = dst_key_alg(key);
 781	sig.labels = 0; /* the root name */
 782	sig.originalttl = 0;
 783
 784	isc_stdtime_get(&now);
 785	sig.timesigned = now - DNS_TSIG_FUDGE;
 786	sig.timeexpire = now + DNS_TSIG_FUDGE;
 787
 788	sig.keyid = dst_key_id(key);
 789
 790	dns_name_init(&sig.signer, NULL);
 791	dns_name_clone(dst_key_name(key), &sig.signer);
 792
 793	sig.siglen = 0;
 794	sig.signature = NULL;
 795
 796	isc_buffer_init(&databuf, data, sizeof(data));
 797
 798	RETERR(dst_context_create(key, mctx, &ctx));
 799
 800	/*
 801	 * Digest the fields of the SIG - we can cheat and use
 802	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
 803	 * is identical to dns format.
 804	 */
 805	RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
 806				    dns_rdatatype_sig /* SIG(0) */,
 807				    &sig, &databuf));
 808	isc_buffer_usedregion(&databuf, &r);
 809	RETERR(dst_context_adddata(ctx, &r));
 810
 811	/*
 812	 * If this is a response, digest the query.
 813	 */
 814	if (is_response(msg))
 815		RETERR(dst_context_adddata(ctx, &msg->query));
 816
 817	/*
 818	 * Digest the header.
 819	 */
 820	isc_buffer_init(&headerbuf, header, sizeof(header));
 821	dns_message_renderheader(msg, &headerbuf);
 822	isc_buffer_usedregion(&headerbuf, &r);
 823	RETERR(dst_context_adddata(ctx, &r));
 824
 825	/*
 826	 * Digest the remainder of the message.
 827	 */
 828	isc_buffer_usedregion(msg->buffer, &r);
 829	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
 830	RETERR(dst_context_adddata(ctx, &r));
 831
 832	RETERR(dst_key_sigsize(key, &sigsize));
 833	sig.siglen = sigsize;
 834	sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
 835	if (sig.signature == NULL) {
 836		result = ISC_R_NOMEMORY;
 837		goto failure;
 838	}
 839
 840	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
 841	RETERR(dst_context_sign(ctx, &sigbuf));
 842	dst_context_destroy(&ctx);
 843
 844	rdata = NULL;
 845	RETERR(dns_message_gettemprdata(msg, &rdata));
 846	RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
 847	RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
 848				    dns_rdatatype_sig /* SIG(0) */,
 849				    &sig, dynbuf));
 850
 851	isc_mem_put(mctx, sig.signature, sig.siglen);
 852	signeedsfree = ISC_FALSE;
 853
 854	dns_message_takebuffer(msg, &dynbuf);
 855
 856	datalist = NULL;
 857	RETERR(dns_message_gettemprdatalist(msg, &datalist));
 858	datalist->rdclass = dns_rdataclass_any;
 859	datalist->type = dns_rdatatype_sig;	/* SIG(0) */
 860	datalist->covers = 0;
 861	datalist->ttl = 0;
 862	ISC_LIST_INIT(datalist->rdata);
 863	ISC_LIST_APPEND(datalist->rdata, rdata, link);
 864	dataset = NULL;
 865	RETERR(dns_message_gettemprdataset(msg, &dataset));
 866	dns_rdataset_init(dataset);
 867	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
 868	msg->sig0 = dataset;
 869
 870	return (ISC_R_SUCCESS);
 871
 872failure:
 873	if (dynbuf != NULL)
 874		isc_buffer_free(&dynbuf);
 875	if (signeedsfree)
 876		isc_mem_put(mctx, sig.signature, sig.siglen);
 877	if (ctx != NULL)
 878		dst_context_destroy(&ctx);
 879
 880	return (result);
 881}
 882
 883isc_result_t
 884dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
 885			 dst_key_t *key)
 886{
 887	dns_rdata_sig_t sig;	/* SIG(0) */
 888	unsigned char header[DNS_MESSAGE_HEADERLEN];
 889	dns_rdata_t rdata = DNS_RDATA_INIT;
 890	isc_region_t r, source_r, sig_r, header_r;
 891	isc_stdtime_t now;
 892	dst_context_t *ctx = NULL;
 893	isc_mem_t *mctx;
 894	isc_result_t result;
 895	isc_uint16_t addcount;
 896	isc_boolean_t signeedsfree = ISC_FALSE;
 897
 898	REQUIRE(source != NULL);
 899	REQUIRE(msg != NULL);
 900	REQUIRE(key != NULL);
 901
 902	mctx = msg->mctx;
 903
 904	msg->verify_attempted = 1;
 905
 906	if (is_response(msg)) {
 907		if (msg->query.base == NULL)
 908			return (DNS_R_UNEXPECTEDTSIG);
 909	}
 910
 911	isc_buffer_usedregion(source, &source_r);
 912
 913	RETERR(dns_rdataset_first(msg->sig0));
 914	dns_rdataset_current(msg->sig0, &rdata);
 915
 916	RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
 917	signeedsfree = ISC_TRUE;
 918
 919	if (sig.labels != 0) {
 920		result = DNS_R_SIGINVALID;
 921		goto failure;
 922	}
 923
 924	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
 925		result = DNS_R_SIGINVALID;
 926		msg->sig0status = dns_tsigerror_badtime;
 927		goto failure;
 928	}
 929
 930	isc_stdtime_get(&now);
 931	if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
 932		result = DNS_R_SIGFUTURE;
 933		msg->sig0status = dns_tsigerror_badtime;
 934		goto failure;
 935	}
 936	else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
 937		result = DNS_R_SIGEXPIRED;
 938		msg->sig0status = dns_tsigerror_badtime;
 939		goto failure;
 940	}
 941
 942	if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
 943		result = DNS_R_SIGINVALID;
 944		msg->sig0status = dns_tsigerror_badkey;
 945		goto failure;
 946	}
 947
 948	RETERR(dst_context_create(key, mctx, &ctx));
 949
 950	/*
 951	 * Digest the SIG(0) record, except for the signature.
 952	 */
 953	dns_rdata_toregion(&rdata, &r);
 954	r.length -= sig.siglen;
 955	RETERR(dst_context_adddata(ctx, &r));
 956
 957	/*
 958	 * If this is a response, digest the query.
 959	 */
 960	if (is_response(msg))
 961		RETERR(dst_context_adddata(ctx, &msg->query));
 962
 963	/*
 964	 * Extract the header.
 965	 */
 966	memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);
 967
 968	/*
 969	 * Decrement the additional field counter.
 970	 */
 971	memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
 972	addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
 973	memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
 974
 975	/*
 976	 * Digest the modified header.
 977	 */
 978	header_r.base = (unsigned char *) header;
 979	header_r.length = DNS_MESSAGE_HEADERLEN;
 980	RETERR(dst_context_adddata(ctx, &header_r));
 981
 982	/*
 983	 * Digest all non-SIG(0) records.
 984	 */
 985	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
 986	r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
 987	RETERR(dst_context_adddata(ctx, &r));
 988
 989	sig_r.base = sig.signature;
 990	sig_r.length = sig.siglen;
 991	result = dst_context_verify(ctx, &sig_r);
 992	if (result != ISC_R_SUCCESS) {
 993		msg->sig0status = dns_tsigerror_badsig;
 994		goto failure;
 995	}
 996
 997	msg->verified_sig = 1;
 998
 999	dst_context_destroy(&ctx);
1000	dns_rdata_freestruct(&sig);
1001
1002	return (ISC_R_SUCCESS);
1003
1004failure:
1005	if (signeedsfree)
1006		dns_rdata_freestruct(&sig);
1007	if (ctx != NULL)
1008		dst_context_destroy(&ctx);
1009
1010	return (result);
1011}
1012
1013/*%
1014 * Does this key ('rdata') self sign the rrset ('rdataset')?
1015 */
1016isc_boolean_t
1017dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
1018		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1019		     isc_boolean_t ignoretime, isc_mem_t *mctx)
1020{
1021	INSIST(rdataset->type == dns_rdatatype_key ||
1022	       rdataset->type == dns_rdatatype_dnskey);
1023	if (rdataset->type == dns_rdatatype_key) {
1024		INSIST(sigrdataset->type == dns_rdatatype_sig);
1025		INSIST(sigrdataset->covers == dns_rdatatype_key);
1026	} else {
1027		INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1028		INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1029	}
1030
1031	return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
1032				 ignoretime, mctx));
1033
1034}
1035
1036isc_boolean_t
1037dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name,
1038		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1039		     isc_boolean_t ignoretime, isc_mem_t *mctx)
1040{
1041	dst_key_t *dstkey = NULL;
1042	dns_keytag_t keytag;
1043	dns_rdata_dnskey_t key;
1044	dns_rdata_rrsig_t sig;
1045	dns_rdata_t sigrdata = DNS_RDATA_INIT;
1046	isc_result_t result;
1047
1048	INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1049	if (sigrdataset->covers != rdataset->type)
1050		return (ISC_FALSE);
1051
1052	result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1053	if (result != ISC_R_SUCCESS)
1054		return (ISC_FALSE);
1055	result = dns_rdata_tostruct(rdata, &key, NULL);
1056	RUNTIME_CHECK(result == ISC_R_SUCCESS);
1057
1058	keytag = dst_key_id(dstkey);
1059	for (result = dns_rdataset_first(sigrdataset);
1060	     result == ISC_R_SUCCESS;
1061	     result = dns_rdataset_next(sigrdataset))
1062	{
1063		dns_rdata_reset(&sigrdata);
1064		dns_rdataset_current(sigrdataset, &sigrdata);
1065		result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1066		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1067
1068		if (sig.algorithm == key.algorithm &&
1069		    sig.keyid == keytag) {
1070			result = dns_dnssec_verify2(name, rdataset, dstkey,
1071						    ignoretime, mctx,
1072						    &sigrdata, NULL);
1073			if (result == ISC_R_SUCCESS) {
1074				dst_key_free(&dstkey);
1075				return (ISC_TRUE);
1076			}
1077		}
1078	}
1079	dst_key_free(&dstkey);
1080	return (ISC_FALSE);
1081}
1082
1083isc_result_t
1084dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1085		     dns_dnsseckey_t **dkp)
1086{
1087	isc_result_t result;
1088	dns_dnsseckey_t *dk;
1089	int major, minor;
1090
1091	REQUIRE(dkp != NULL && *dkp == NULL);
1092	dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1093	if (dk == NULL)
1094		return (ISC_R_NOMEMORY);
1095
1096	dk->key = *dstkey;
1097	*dstkey = NULL;
1098	dk->force_publish = ISC_FALSE;
1099	dk->force_sign = ISC_FALSE;
1100	dk->hint_publish = ISC_FALSE;
1101	dk->hint_sign = ISC_FALSE;
1102	dk->hint_remove = ISC_FALSE;
1103	dk->first_sign = ISC_FALSE;
1104	dk->is_active = ISC_FALSE;
1105	dk->prepublish = 0;
1106	dk->source = dns_keysource_unknown;
1107	dk->index = 0;
1108
1109	/* KSK or ZSK? */
1110	dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1111
1112	/* Is this an old-style key? */
1113	result = dst_key_getprivateformat(dk->key, &major, &minor);
1114	INSIST(result == ISC_R_SUCCESS);
1115
1116	/* Smart signing started with key format 1.3 */
1117	dk->legacy = ISC_TF(major == 1 && minor <= 2);
1118
1119	ISC_LINK_INIT(dk, link);
1120	*dkp = dk;
1121	return (ISC_R_SUCCESS);
1122}
1123
1124void
1125dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1126	dns_dnsseckey_t *dk;
1127
1128	REQUIRE(dkp != NULL && *dkp != NULL);
1129	dk = *dkp;
1130	if (dk->key != NULL)
1131		dst_key_free(&dk->key);
1132	isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1133	*dkp = NULL;
1134}
1135
1136static void
1137get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1138	isc_result_t result;
1139	isc_stdtime_t publish, active, revoke, inactive, delete;
1140	isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
1141	isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
1142	isc_boolean_t delset = ISC_FALSE;
1143
1144	REQUIRE(key != NULL && key->key != NULL);
1145
1146	result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1147	if (result == ISC_R_SUCCESS)
1148		pubset = ISC_TRUE;
1149
1150	result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1151	if (result == ISC_R_SUCCESS)
1152		actset = ISC_TRUE;
1153
1154	result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1155	if (result == ISC_R_SUCCESS)
1156		revset = ISC_TRUE;
1157
1158	result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1159	if (result == ISC_R_SUCCESS)
1160		inactset = ISC_TRUE;
1161
1162	result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1163	if (result == ISC_R_SUCCESS)
1164		delset = ISC_TRUE;
1165
1166	/* Metadata says publish (but possibly not activate) */
1167	if (pubset && publish <= now)
1168		key->hint_publish = ISC_TRUE;
1169
1170	/* Metadata says activate (so we must also publish) */
1171	if (actset && active <= now) {
1172		key->hint_sign = ISC_TRUE;
1173		key->hint_publish = ISC_TRUE;
1174	}
1175
1176	/*
1177	 * Activation date is set (maybe in the future), but
1178	 * publication date isn't. Most likely the user wants to
1179	 * publish now and activate later.
1180	 */
1181	if (actset && !pubset)
1182		key->hint_publish = ISC_TRUE;
1183
1184	/*
1185	 * If activation date is in the future, make note of how far off
1186	 */
1187	if (key->hint_publish && actset && active > now) {
1188		key->prepublish = active - now;
1189	}
1190
1191	/*
1192	 * Key has been marked inactive: we can continue publishing,
1193	 * but don't sign.
1194	 */
1195	if (key->hint_publish && inactset && inactive <= now) {
1196		key->hint_sign = ISC_FALSE;
1197	}
1198
1199	/*
1200	 * Metadata says revoke.  If the key is published,
1201	 * we *have to* sign with it per RFC5011--even if it was
1202	 * not active before.
1203	 *
1204	 * If it hasn't already been done, we should also revoke it now.
1205	 */
1206	if (key->hint_publish && (revset && revoke <= now)) {
1207		isc_uint32_t flags;
1208		key->hint_sign = ISC_TRUE;
1209		flags = dst_key_flags(key->key);
1210		if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1211			flags |= DNS_KEYFLAG_REVOKE;
1212			dst_key_setflags(key->key, flags);
1213		}
1214	}
1215
1216	/*
1217	 * Metadata says delete, so don't publish this key or sign with it.
1218	 */
1219	if (delset && delete <= now) {
1220		key->hint_publish = ISC_FALSE;
1221		key->hint_sign = ISC_FALSE;
1222		key->hint_remove = ISC_TRUE;
1223	}
1224}
1225
1226/*%
1227 * Get a list of DNSSEC keys from the key repository
1228 */
1229isc_result_t
1230dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1231			    isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1232{
1233	isc_result_t result = ISC_R_SUCCESS;
1234	isc_boolean_t dir_open = ISC_FALSE;
1235	dns_dnsseckeylist_t list;
1236	isc_dir_t dir;
1237	dns_dnsseckey_t *key = NULL;
1238	dst_key_t *dstkey = NULL;
1239	char namebuf[DNS_NAME_FORMATSIZE], *p;
1240	isc_buffer_t b;
1241	unsigned int len;
1242	isc_stdtime_t now;
1243
1244	REQUIRE(keylist != NULL);
1245	ISC_LIST_INIT(list);
1246	isc_dir_init(&dir);
1247
1248	isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1249	RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
1250	len = isc_buffer_usedlength(&b);
1251	namebuf[len] = '\0';
1252
1253	if (directory == NULL)
1254		directory = ".";
1255	RETERR(isc_dir_open(&dir, directory));
1256	dir_open = ISC_TRUE;
1257
1258	isc_stdtime_get(&now);
1259
1260	while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1261		if (dir.entry.name[0] == 'K' &&
1262		    dir.entry.length > len + 1 &&
1263		    dir.entry.name[len + 1] == '+' &&
1264		    strncasecmp(dir.entry.name + 1, namebuf, len) == 0) {
1265			p = strrchr(dir.entry.name, '.');
1266			if (p != NULL && strcmp(p, ".private") != 0)
1267				continue;
1268
1269			dstkey = NULL;
1270			result = dst_key_fromnamedfile(dir.entry.name,
1271						       directory,
1272						       DST_TYPE_PUBLIC |
1273						       DST_TYPE_PRIVATE,
1274						       mctx, &dstkey);
1275
1276			if (result != ISC_R_SUCCESS) {
1277				isc_log_write(dns_lctx,
1278					      DNS_LOGCATEGORY_GENERAL,
1279					      DNS_LOGMODULE_DNSSEC,
1280					      ISC_LOG_WARNING,
1281					      "dns_dnssec_findmatchingkeys: "
1282					      "error reading key file %s: %s",
1283					      dir.entry.name,
1284					      isc_result_totext(result));
1285				continue;
1286			}
1287
1288			RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1289			key->source = dns_keysource_repository;
1290			get_hints(key, now);
1291
1292			if (key->legacy) {
1293				dns_dnsseckey_destroy(mctx, &key);
1294			} else {
1295				ISC_LIST_APPEND(list, key, link);
1296				key = NULL;
1297			}
1298		}
1299	}
1300
1301	if (!ISC_LIST_EMPTY(list))
1302		ISC_LIST_APPENDLIST(*keylist, list, link);
1303	else
1304		result = ISC_R_NOTFOUND;
1305
1306 failure:
1307	if (dir_open)
1308		isc_dir_close(&dir);
1309	INSIST(key == NULL);
1310	while ((key = ISC_LIST_HEAD(list)) != NULL) {
1311		ISC_LIST_UNLINK(list, key, link);
1312		INSIST(key->key != NULL);
1313		dst_key_free(&key->key);
1314		dns_dnsseckey_destroy(mctx, &key);
1315	}
1316	if (dstkey != NULL)
1317		dst_key_free(&dstkey);
1318	return (result);
1319}
1320
1321/*%
1322 * Add 'newkey' to 'keylist' if it's not already there.
1323 *
1324 * If 'savekeys' is ISC_TRUE, then we need to preserve all
1325 * the keys in the keyset, regardless of whether they have
1326 * metadata indicating they should be deactivated or removed.
1327 */
1328static void
1329addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1330       isc_boolean_t savekeys, isc_mem_t *mctx)
1331{
1332	dns_dnsseckey_t *key;
1333
1334	/* Skip duplicates */
1335	for (key = ISC_LIST_HEAD(*keylist);
1336	     key != NULL;
1337	     key = ISC_LIST_NEXT(key, link)) {
1338		if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1339		    dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1340		    dns_name_equal(dst_key_name(key->key),
1341				   dst_key_name(*newkey)))
1342			break;
1343	}
1344
1345	if (key != NULL) {
1346		/*
1347		 * Found a match.  If the old key was only public and the
1348		 * new key is private, replace the old one; otherwise
1349		 * leave it.  But either way, mark the key as having
1350		 * been found in the zone.
1351		 */
1352		if (dst_key_isprivate(key->key)) {
1353			dst_key_free(newkey);
1354		} else if (dst_key_isprivate(*newkey)) {
1355			dst_key_free(&key->key);
1356			key->key = *newkey;
1357		}
1358
1359		key->source = dns_keysource_zoneapex;
1360		return;
1361	}
1362
1363	dns_dnsseckey_create(mctx, newkey, &key);
1364	if (key->legacy || savekeys) {
1365		key->force_publish = ISC_TRUE;
1366		key->force_sign = dst_key_isprivate(key->key);
1367	}
1368	key->source = dns_keysource_zoneapex;
1369	ISC_LIST_APPEND(*keylist, key, link);
1370	*newkey = NULL;
1371}
1372
1373
1374/*%
1375 * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1376 * for future reference.
1377 */
1378static isc_result_t
1379mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1380	isc_result_t result = ISC_R_SUCCESS;
1381	dns_rdata_t rdata = DNS_RDATA_INIT;
1382	dns_rdataset_t sigs;
1383	dns_dnsseckey_t *key;
1384
1385	REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1386
1387	dns_rdataset_init(&sigs);
1388	dns_rdataset_clone(rrsigs, &sigs);
1389	for (key = ISC_LIST_HEAD(*keylist);
1390	     key != NULL;
1391	     key = ISC_LIST_NEXT(key, link)) {
1392		isc_uint16_t keyid, sigid;
1393		dns_secalg_t keyalg, sigalg;
1394		keyid = dst_key_id(key->key);
1395		keyalg = dst_key_alg(key->key);
1396
1397		for (result = dns_rdataset_first(&sigs);
1398		     result == ISC_R_SUCCESS;
1399		     result = dns_rdataset_next(&sigs)) {
1400			dns_rdata_rrsig_t sig;
1401
1402			dns_rdata_reset(&rdata);
1403			dns_rdataset_current(&sigs, &rdata);
1404			result = dns_rdata_tostruct(&rdata, &sig, NULL);
1405			RUNTIME_CHECK(result == ISC_R_SUCCESS);
1406			sigalg = sig.algorithm;
1407			sigid = sig.keyid;
1408			if (keyid == sigid && keyalg == sigalg) {
1409				key->is_active = ISC_TRUE;
1410				break;
1411			}
1412		}
1413	}
1414
1415	if (result == ISC_R_NOMORE)
1416		result = ISC_R_SUCCESS;
1417
1418	if (dns_rdataset_isassociated(&sigs))
1419		dns_rdataset_disassociate(&sigs);
1420	return (result);
1421}
1422
1423/*%
1424 * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1425 */
1426isc_result_t
1427dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1428			       const char *directory, isc_mem_t *mctx,
1429			       dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1430			       dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1431			       isc_boolean_t public,
1432			       dns_dnsseckeylist_t *keylist)
1433{
1434	dns_rdataset_t keys;
1435	dns_rdata_t rdata = DNS_RDATA_INIT;
1436	dst_key_t *pubkey = NULL, *privkey = NULL;
1437	isc_result_t result;
1438
1439	REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1440
1441	dns_rdataset_init(&keys);
1442
1443	dns_rdataset_clone(keyset, &keys);
1444	for (result = dns_rdataset_first(&keys);
1445	     result == ISC_R_SUCCESS;
1446	     result = dns_rdataset_next(&keys)) {
1447		dns_rdata_reset(&rdata);
1448		dns_rdataset_current(&keys, &rdata);
1449		RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1450
1451		if (!is_zone_key(pubkey) ||
1452		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1453			goto skip;
1454
1455		/* Corrupted .key file? */
1456		if (!dns_name_equal(origin, dst_key_name(pubkey)))
1457			goto skip;
1458
1459		if (public) {
1460			addkey(keylist, &pubkey, savekeys, mctx);
1461			goto skip;
1462		}
1463
1464		result = dst_key_fromfile(dst_key_name(pubkey),
1465					  dst_key_id(pubkey),
1466					  dst_key_alg(pubkey),
1467					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1468					  directory, mctx, &privkey);
1469
1470		/*
1471		 * If the key was revoked and the private file
1472		 * doesn't exist, maybe it was revoked internally
1473		 * by named.  Try loading the unrevoked version.
1474		 */
1475		if (result == ISC_R_FILENOTFOUND) {
1476			isc_uint32_t flags;
1477			flags = dst_key_flags(pubkey);
1478			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1479				dst_key_setflags(pubkey,
1480						 flags & ~DNS_KEYFLAG_REVOKE);
1481				result = dst_key_fromfile(dst_key_name(pubkey),
1482							  dst_key_id(pubkey),
1483							  dst_key_alg(pubkey),
1484							  DST_TYPE_PUBLIC|
1485							  DST_TYPE_PRIVATE,
1486							  directory,
1487							  mctx, &privkey);
1488				if (result == ISC_R_SUCCESS &&
1489				    dst_key_pubcompare(pubkey, privkey,
1490						       ISC_FALSE)) {
1491					dst_key_setflags(privkey, flags);
1492				}
1493				dst_key_setflags(pubkey, flags);
1494			}
1495		}
1496
1497		if (result != ISC_R_SUCCESS) {
1498			char keybuf[DNS_NAME_FORMATSIZE];
1499			char algbuf[DNS_SECALG_FORMATSIZE];
1500			dns_name_format(dst_key_name(pubkey), keybuf,
1501					sizeof(keybuf));
1502			dns_secalg_format(dst_key_alg(pubkey), algbuf,
1503					  sizeof(algbuf));
1504			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1505				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1506				      "dns_dnssec_keylistfromrdataset: error "
1507				      "reading private key file %s/%s/%d: %s",
1508				      keybuf, algbuf, dst_key_id(pubkey),
1509				      isc_result_totext(result));
1510		}
1511
1512		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1513			addkey(keylist, &pubkey, savekeys, mctx);
1514			goto skip;
1515		}
1516		RETERR(result);
1517
1518		/* This should never happen. */
1519		if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1520			goto skip;
1521
1522		addkey(keylist, &privkey, savekeys, mctx);
1523 skip:
1524		if (pubkey != NULL)
1525			dst_key_free(&pubkey);
1526		if (privkey != NULL)
1527			dst_key_free(&privkey);
1528	}
1529
1530	if (result != ISC_R_NOMORE)
1531		RETERR(result);
1532
1533	if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1534		RETERR(mark_active_keys(keylist, keysigs));
1535
1536	if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1537		RETERR(mark_active_keys(keylist, soasigs));
1538
1539	result = ISC_R_SUCCESS;
1540
1541 failure:
1542	if (dns_rdataset_isassociated(&keys))
1543		dns_rdataset_disassociate(&keys);
1544	if (pubkey != NULL)
1545		dst_key_free(&pubkey);
1546	if (privkey != NULL)
1547		dst_key_free(&privkey);
1548	return (result);
1549}
1550
1551static isc_result_t
1552make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1553	    dns_rdata_t *target)
1554{
1555	isc_result_t result;
1556	isc_buffer_t b;
1557	isc_region_t r;
1558
1559	isc_buffer_init(&b, buf, bufsize);
1560	result = dst_key_todns(key, &b);
1561	if (result != ISC_R_SUCCESS)
1562		return (result);
1563
1564	dns_rdata_reset(target);
1565	isc_buffer_usedregion(&b, &r);
1566	dns_rdata_fromregion(target, dst_key_class(key),
1567			     dns_rdatatype_dnskey, &r);
1568	return (ISC_R_SUCCESS);
1569}
1570
1571static isc_result_t
1572publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1573	    dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1574	    void (*report)(const char *, ...))
1575{
1576	isc_result_t result;
1577	dns_difftuple_t *tuple = NULL;
1578	unsigned char buf[DST_KEY_MAXSIZE];
1579	dns_rdata_t dnskey = DNS_RDATA_INIT;
1580	char alg[80];
1581
1582	dns_rdata_reset(&dnskey);
1583	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1584
1585	dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1586	report("Fetching %s %d/%s from key %s.",
1587	       key->ksk ?  (allzsk ?  "KSK/ZSK" : "KSK") : "ZSK",
1588	       dst_key_id(key->key), alg,
1589	       key->source == dns_keysource_user ?  "file" : "repository");
1590
1591	if (key->prepublish && ttl > key->prepublish) {
1592		char keystr[DST_KEY_FORMATSIZE];
1593		isc_stdtime_t now;
1594
1595		dst_key_format(key->key, keystr, sizeof(keystr));
1596		report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1597		       keystr, ttl);
1598
1599		isc_stdtime_get(&now);
1600		dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1601	}
1602
1603	/* publish key */
1604	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1605				    &dnskey, &tuple));
1606	dns_diff_appendminimal(diff, &tuple);
1607	result = ISC_R_SUCCESS;
1608
1609 failure:
1610	return (result);
1611}
1612
1613static isc_result_t
1614remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1615	  dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1616	  void (*report)(const char *, ...))
1617{
1618	isc_result_t result;
1619	dns_difftuple_t *tuple = NULL;
1620	unsigned char buf[DST_KEY_MAXSIZE];
1621	dns_rdata_t dnskey = DNS_RDATA_INIT;
1622	char alg[80];
1623
1624	dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1625	report("Removing %s key %d/%s from DNSKEY RRset.",
1626	       reason, dst_key_id(key->key), alg);
1627
1628	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1629	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1630				    &tuple));
1631	dns_diff_appendminimal(diff, &tuple);
1632	result = ISC_R_SUCCESS;
1633
1634 failure:
1635	return (result);
1636}
1637
1638/*
1639 * Update 'keys' with information from 'newkeys'.
1640 *
1641 * If 'removed' is not NULL, any keys that are being removed from
1642 * the zone will be added to the list for post-removal processing.
1643 */
1644isc_result_t
1645dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1646		      dns_dnsseckeylist_t *removed, dns_name_t *origin,
1647		      dns_ttl_t ttl, dns_diff_t *diff, isc_boolean_t allzsk,
1648		      isc_mem_t *mctx, void (*report)(const char *, ...))
1649{
1650	isc_result_t result;
1651	dns_dnsseckey_t *key, *key1, *key2, *next;
1652
1653	/*
1654	 * First, look through the existing key list to find keys
1655	 * supplied from the command line which are not in the zone.
1656	 * Update the zone to include them.
1657	 */
1658	for (key = ISC_LIST_HEAD(*keys);
1659	     key != NULL;
1660	     key = ISC_LIST_NEXT(key, link)) {
1661		if (key->source == dns_keysource_user &&
1662		    (key->hint_publish || key->force_publish)) {
1663			RETERR(publish_key(diff, key, origin, ttl,
1664					   mctx, allzsk, report));
1665		}
1666	}
1667
1668	/*
1669	 * Second, scan the list of newly found keys looking for matches
1670	 * with known keys, and update accordingly.
1671	 */
1672	for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1673		isc_boolean_t key_revoked = ISC_FALSE;
1674
1675		next = ISC_LIST_NEXT(key1, link);
1676
1677		for (key2 = ISC_LIST_HEAD(*keys);
1678		     key2 != NULL;
1679		     key2 = ISC_LIST_NEXT(key2, link)) {
1680			if (dst_key_pubcompare(key1->key, key2->key,
1681					       ISC_TRUE)) {
1682				int r1, r2;
1683				r1 = dst_key_flags(key1->key) &
1684					DNS_KEYFLAG_REVOKE;
1685				r2 = dst_key_flags(key2->key) &
1686					DNS_KEYFLAG_REVOKE;
1687				key_revoked = ISC_TF(r1 != r2);
1688				break;
1689			}
1690		}
1691
1692		/* No match found in keys; add the new key. */
1693		if (key2 == NULL) {
1694			ISC_LIST_UNLINK(*newkeys, key1, link);
1695			ISC_LIST_APPEND(*keys, key1, link);
1696
1697			if (key1->source != dns_keysource_zoneapex &&
1698			    (key1->hint_publish || key1->force_publish)) {
1699				RETERR(publish_key(diff, key1, origin, ttl,
1700						   mctx, allzsk, report));
1701				if (key1->hint_sign || key1->force_sign)
1702					key1->first_sign = ISC_TRUE;
1703			}
1704
1705			continue;
1706		}
1707
1708		/* Match found: remove or update it as needed */
1709		if (key1->hint_remove) {
1710			RETERR(remove_key(diff, key2, origin, ttl, mctx,
1711					  "expired", report));
1712			ISC_LIST_UNLINK(*keys, key2, link);
1713			if (removed != NULL)
1714				ISC_LIST_APPEND(*removed, key2, link);
1715			else
1716				dns_dnsseckey_destroy(mctx, &key2);
1717		} else if (key_revoked &&
1718			 (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1719
1720			/*
1721			 * A previously valid key has been revoked.
1722			 * We need to remove the old version and pull
1723			 * in the new one.
1724			 */
1725			RETERR(remove_key(diff, key2, origin, ttl, mctx,
1726					  "revoked", report));
1727			ISC_LIST_UNLINK(*keys, key2, link);
1728			if (removed != NULL)
1729				ISC_LIST_APPEND(*removed, key2, link);
1730			else
1731				dns_dnsseckey_destroy(mctx, &key2);
1732
1733			RETERR(publish_key(diff, key1, origin, ttl,
1734					   mctx, allzsk, report));
1735			ISC_LIST_UNLINK(*newkeys, key1, link);
1736			ISC_LIST_APPEND(*keys, key1, link);
1737
1738			/*
1739			 * XXX: The revoke flag is only defined for trust
1740			 * anchors.  Setting the flag on a non-KSK is legal,
1741			 * but not defined in any RFC.  It seems reasonable
1742			 * to treat it the same as a KSK: keep it in the
1743			 * zone, sign the DNSKEY set with it, but not
1744			 * sign other records with it.
1745			 */
1746			key1->ksk = ISC_TRUE;
1747			continue;
1748		} else {
1749			if (!key2->is_active &&
1750			    (key1->hint_sign || key1->force_sign))
1751				key2->first_sign = ISC_TRUE;
1752			key2->hint_sign = key1->hint_sign;
1753			key2->hint_publish = key1->hint_publish;
1754		}
1755	}
1756
1757	/* Free any leftover keys in newkeys */
1758	while (!ISC_LIST_EMPTY(*newkeys)) {
1759		key1 = ISC_LIST_HEAD(*newkeys);
1760		ISC_LIST_UNLINK(*newkeys, key1, link);
1761		dns_dnsseckey_destroy(mctx, &key1);
1762	}
1763
1764	result = ISC_R_SUCCESS;
1765
1766 failure:
1767	return (result);
1768}