Beispiel #1
0
isc_result_t
dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
		 dst_key_t **keyp)
{
	REQUIRE(keyp != NULL && *keyp != NULL);
	return (insert(keytable, managed, dst_key_name(*keyp), keyp));
}
Beispiel #2
0
void
key_format(const dst_key_t *key, char *cp, unsigned int size) {
	char namestr[DNS_NAME_FORMATSIZE];
	char algstr[DNS_NAME_FORMATSIZE];

	dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
	alg_format((dns_secalg_t) dst_key_alg(key), algstr, sizeof(algstr));
	snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
}
Beispiel #3
0
static void
loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
	dns_rdata_t *rdata)
{
	isc_result_t  result;
	dst_key_t     *key = NULL;
	isc_buffer_t  keyb;
	isc_region_t  r;

	dns_rdata_init(rdata);

	isc_buffer_init(&keyb, key_buf, key_buf_size);

	result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
				       mctx, &key);
	if (result != ISC_R_SUCCESS)
		fatal("invalid keyfile name %s: %s",
		      filename, isc_result_totext(result));

	if (verbose > 2) {
		char keystr[DST_KEY_FORMATSIZE];

		dst_key_format(key, keystr, sizeof(keystr));
		fprintf(stderr, "%s: %s\n", program, keystr);
	}

	result = dst_key_todns(key, &keyb);
	if (result != ISC_R_SUCCESS)
		fatal("can't decode key");

	isc_buffer_usedregion(&keyb, &r);
	dns_rdata_fromregion(rdata, dst_key_class(key),
			     dns_rdatatype_dnskey, &r);

	rdclass = dst_key_class(key);

	dns_fixedname_init(&fixed);
	name = dns_fixedname_name(&fixed);
	result = dns_name_copy(dst_key_name(key), name, NULL);
	if (result != ISC_R_SUCCESS)
		fatal("can't copy name");

	dst_key_free(&key);
}
isc_result_t
dns_keytable_add(dns_keytable_t *keytable, dst_key_t **keyp) {
	isc_result_t result;
	dns_keynode_t *knode;
	dns_rbtnode_t *node;
	dns_name_t *keyname;

	/*
	 * Add '*keyp' to 'keytable'.
	 */

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(keyp != NULL);

	keyname = dst_key_name(*keyp);

	knode = isc_mem_get(keytable->mctx, sizeof(*knode));
	if (knode == NULL)
		return (ISC_R_NOMEMORY);

	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);

	node = NULL;
	result = dns_rbt_addnode(keytable->table, keyname, &node);

	if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
		knode->magic = KEYNODE_MAGIC;
		knode->key = *keyp;
		knode->next = node->data;
		node->data = knode;
		*keyp = NULL;
		knode = NULL;
		result = ISC_R_SUCCESS;
	}

	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);

	if (knode != NULL)
		isc_mem_put(keytable->mctx, knode, sizeof(*knode));

	return (result);
}
Beispiel #5
0
static void
dns(dst_key_t *key, isc_mem_t *mctx) {
	unsigned char buffer1[2048];
	unsigned char buffer2[2048];
	isc_buffer_t buf1, buf2;
	isc_region_t r1, r2;
	dst_key_t *newkey = NULL;
	isc_result_t ret;
	isc_boolean_t match;

	isc_buffer_init(&buf1, buffer1, sizeof(buffer1));
	ret = dst_key_todns(key, &buf1);
	printf("todns(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	if (ret != ISC_R_SUCCESS)
		return;
	ret = dst_key_fromdns(dst_key_name(key), dns_rdataclass_in,
			      &buf1, mctx, &newkey);
	printf("fromdns(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	if (ret != ISC_R_SUCCESS)
		return;
	isc_buffer_init(&buf2, buffer2, sizeof(buffer2));
	ret = dst_key_todns(newkey, &buf2);
	printf("todns2(%d) returned: %s\n", dst_key_alg(key),
	       isc_result_totext(ret));
	if (ret != ISC_R_SUCCESS)
		return;
	isc_buffer_usedregion(&buf1, &r1);
	isc_buffer_usedregion(&buf2, &r2);
	match = ISC_TF(r1.length == r2.length &&
		       memcmp(r1.base, r2.base, r1.length) == 0);
	printf("compare(%d): %s\n", dst_key_alg(key),
	       match ? "true" : "false");
	dst_key_free(&newkey);
}
Beispiel #6
0
isc_result_t
dns_tsec_create(isc_mem_t *mctx, dns_tsectype_t type, dst_key_t *key,
		dns_tsec_t **tsecp)
{
	isc_result_t result;
	dns_tsec_t *tsec;
	dns_tsigkey_t *tsigkey = NULL;
	dns_name_t *algname;

	REQUIRE(mctx != NULL);
	REQUIRE(tsecp != NULL && *tsecp == NULL);

	tsec = isc_mem_get(mctx, sizeof(*tsec));
	if (tsec == NULL)
		return (ISC_R_NOMEMORY);

	tsec->type = type;
	tsec->mctx = mctx;

	switch (type) {
	case dns_tsectype_tsig:
		switch (dst_key_alg(key)) {
		case DST_ALG_HMACMD5:
			algname = dns_tsig_hmacmd5_name;
			break;
		case DST_ALG_HMACSHA1:
			algname = dns_tsig_hmacsha1_name;
			break;
		case DST_ALG_HMACSHA224:
			algname = dns_tsig_hmacsha224_name;
			break;
		case DST_ALG_HMACSHA256:
			algname = dns_tsig_hmacsha256_name;
			break;
		case DST_ALG_HMACSHA384:
			algname = dns_tsig_hmacsha384_name;
			break;
		case DST_ALG_HMACSHA512:
			algname = dns_tsig_hmacsha512_name;
			break;
		default:
			isc_mem_put(mctx, tsec, sizeof(*tsec));
			return (DNS_R_BADALG);
		}
		result = dns_tsigkey_createfromkey(dst_key_name(key),
						   algname, key, ISC_FALSE,
						   NULL, 0, 0, mctx, NULL,
						   &tsigkey);
		if (result != ISC_R_SUCCESS) {
			isc_mem_put(mctx, tsec, sizeof(*tsec));
			return (result);
		}
		tsec->ukey.tsigkey = tsigkey;
		break;
	case dns_tsectype_sig0:
		tsec->ukey.key = key;
		break;
	default:
		INSIST(0);
	}

	tsec->magic = DNS_TSEC_MAGIC;

	*tsecp = tsec;
	return (ISC_R_SUCCESS);
}
isc_result_t
dns_keytable_deletekeynode(dns_keytable_t *keytable, dst_key_t *dstkey) {
	isc_result_t result;
	dns_name_t *keyname;
	dns_rbtnode_t *node = NULL;
	dns_keynode_t *knode = NULL, **kprev = NULL;

	REQUIRE(VALID_KEYTABLE(keytable));
	REQUIRE(dstkey != NULL);

	keyname = dst_key_name(dstkey);

	RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
	result = dns_rbt_findnode(keytable->table, keyname, NULL, &node, NULL,
				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);

	if (result == DNS_R_PARTIALMATCH)
		result = ISC_R_NOTFOUND;
	if (result != ISC_R_SUCCESS)
		goto finish;

	if (node->data == NULL) {
		result = ISC_R_NOTFOUND;
		goto finish;
	}

	knode = node->data;
	if (knode->next == NULL && knode->key != NULL &&
	    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
	{
		result = dns_rbt_deletenode(keytable->table, node, ISC_FALSE);
		goto finish;
	}

	kprev = (dns_keynode_t **)(void *)&node->data;
	while (knode != NULL) {
		if (knode->key != NULL &&
		    dst_key_compare(knode->key, dstkey) == ISC_TRUE)
			break;
		kprev = &knode->next;
		knode = knode->next;
	}

	if (knode != NULL) {
		if (knode->key != NULL)
			dst_key_free(&knode->key);
		/*
		 * This is equivalent to:
		 * dns_keynode_attach(knode->next, &tmp);
		 * dns_keynode_detach(kprev);
		 * dns_keynode_attach(tmp, &kprev);
		 * dns_keynode_detach(&tmp);
		 */
		*kprev = knode->next;
		knode->next = NULL;
		dns_keynode_detach(keytable->mctx, &knode);
	} else
		result = DNS_R_PARTIALMATCH;
  finish:
	RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
	return (result);
}
Beispiel #8
0
static isc_result_t
process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
	       dns_rdata_tkey_t *tkeyin, dns_tkeyctx_t *tctx,
	       dns_rdata_tkey_t *tkeyout,
	       dns_tsig_keyring_t *ring, dns_namelist_t *namelist)
{
	isc_result_t result = ISC_R_SUCCESS;
	dns_name_t *keyname, ourname;
	dns_rdataset_t *keyset = NULL;
	dns_rdata_t keyrdata = DNS_RDATA_INIT, ourkeyrdata = DNS_RDATA_INIT;
	isc_boolean_t found_key = ISC_FALSE, found_incompatible = ISC_FALSE;
	dst_key_t *pubkey = NULL;
	isc_buffer_t ourkeybuf, *shared = NULL;
	isc_region_t r, r2, ourkeyr;
	unsigned char keydata[DST_KEY_MAXSIZE];
	unsigned int sharedsize;
	isc_buffer_t secret;
	unsigned char *randomdata = NULL, secretdata[256];
	dns_ttl_t ttl = 0;

	if (tctx->dhkey == NULL) {
		tkey_log("process_dhtkey: tkey-dhkey not defined");
		tkeyout->error = dns_tsigerror_badalg;
		return (DNS_R_REFUSED);
	}

	if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) {
		tkey_log("process_dhtkey: algorithms other than "
			 "hmac-md5 are not supported");
		tkeyout->error = dns_tsigerror_badalg;
		return (ISC_R_SUCCESS);
	}

	/*
	 * Look for a DH KEY record that will work with ours.
	 */
	for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL);
	     result == ISC_R_SUCCESS && !found_key;
	     result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) {
		keyname = NULL;
		dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname);
		keyset = NULL;
		result = dns_message_findtype(keyname, dns_rdatatype_key, 0,
					      &keyset);
		if (result != ISC_R_SUCCESS)
			continue;

		for (result = dns_rdataset_first(keyset);
		     result == ISC_R_SUCCESS && !found_key;
		     result = dns_rdataset_next(keyset)) {
			dns_rdataset_current(keyset, &keyrdata);
			pubkey = NULL;
			result = dns_dnssec_keyfromrdata(keyname, &keyrdata,
							 msg->mctx, &pubkey);
			if (result != ISC_R_SUCCESS) {
				dns_rdata_reset(&keyrdata);
				continue;
			}
			if (dst_key_alg(pubkey) == DNS_KEYALG_DH) {
				if (dst_key_paramcompare(pubkey, tctx->dhkey))
				{
					found_key = ISC_TRUE;
					ttl = keyset->ttl;
					break;
				} else
					found_incompatible = ISC_TRUE;
			}
			dst_key_free(&pubkey);
			dns_rdata_reset(&keyrdata);
		}
	}

	if (!found_key) {
		if (found_incompatible) {
			tkey_log("process_dhtkey: found an incompatible key");
			tkeyout->error = dns_tsigerror_badkey;
			return (ISC_R_SUCCESS);
		} else {
			tkey_log("process_dhtkey: failed to find a key");
			return (DNS_R_FORMERR);
		}
	}

	RETERR(add_rdata_to_list(msg, keyname, &keyrdata, ttl, namelist));

	isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata));
	RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf));
	isc_buffer_usedregion(&ourkeybuf, &ourkeyr);
	dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_any,
			     dns_rdatatype_key, &ourkeyr);

	dns_name_init(&ourname, NULL);
	dns_name_clone(dst_key_name(tctx->dhkey), &ourname);

	/*
	 * XXXBEW The TTL should be obtained from the database, if it exists.
	 */
	RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, 0, namelist));

	RETERR(dst_key_secretsize(tctx->dhkey, &sharedsize));
	RETERR(isc_buffer_allocate(msg->mctx, &shared, sharedsize));

	result = dst_key_computesecret(pubkey, tctx->dhkey, shared);
	if (result != ISC_R_SUCCESS) {
		tkey_log("process_dhtkey: failed to compute shared secret: %s",
			 isc_result_totext(result));
		goto failure;
	}
	dst_key_free(&pubkey);

	isc_buffer_init(&secret, secretdata, sizeof(secretdata));

	randomdata = isc_mem_get(tkeyout->mctx, TKEY_RANDOM_AMOUNT);
	if (randomdata == NULL)
		goto failure;

	result = dst__entropy_getdata(randomdata, TKEY_RANDOM_AMOUNT,
				      ISC_FALSE);
	if (result != ISC_R_SUCCESS) {
		tkey_log("process_dhtkey: failed to obtain entropy: %s",
			 isc_result_totext(result));
		goto failure;
	}

	r.base = randomdata;
	r.length = TKEY_RANDOM_AMOUNT;
	r2.base = tkeyin->key;
	r2.length = tkeyin->keylen;
	RETERR(compute_secret(shared, &r2, &r, &secret));
	isc_buffer_free(&shared);

	RETERR(dns_tsigkey_create(name, &tkeyin->algorithm,
				  isc_buffer_base(&secret),
				  isc_buffer_usedlength(&secret),
				  ISC_TRUE, signer, tkeyin->inception,
				  tkeyin->expire, ring->mctx, ring, NULL));

	/* This key is good for a long time */
	tkeyout->inception = tkeyin->inception;
	tkeyout->expire = tkeyin->expire;

	tkeyout->key = randomdata;
	tkeyout->keylen = TKEY_RANDOM_AMOUNT;

	return (ISC_R_SUCCESS);

 failure:
	if (!ISC_LIST_EMPTY(*namelist))
		free_namelist(msg, namelist);
	if (shared != NULL)
		isc_buffer_free(&shared);
	if (pubkey != NULL)
		dst_key_free(&pubkey);
	if (randomdata != NULL)
		isc_mem_put(tkeyout->mctx, randomdata, TKEY_RANDOM_AMOUNT);
	return (result);
}
Beispiel #9
0
isc_result_t
dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
			 dst_key_t *key)
{
	dns_rdata_sig_t sig;	/* SIG(0) */
	unsigned char header[DNS_MESSAGE_HEADERLEN];
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_region_t r, source_r, sig_r, header_r;
	isc_stdtime_t now;
	dst_context_t *ctx = NULL;
	isc_mem_t *mctx;
	isc_result_t result;
	isc_uint16_t addcount;
	isc_boolean_t signeedsfree = ISC_FALSE;

	REQUIRE(source != NULL);
	REQUIRE(msg != NULL);
	REQUIRE(key != NULL);

	mctx = msg->mctx;

	msg->verify_attempted = 1;

	if (is_response(msg)) {
		if (msg->query.base == NULL)
			return (DNS_R_UNEXPECTEDTSIG);
	}

	isc_buffer_usedregion(source, &source_r);

	RETERR(dns_rdataset_first(msg->sig0));
	dns_rdataset_current(msg->sig0, &rdata);

	RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
	signeedsfree = ISC_TRUE;

	if (sig.labels != 0) {
		result = DNS_R_SIGINVALID;
		goto failure;
	}

	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
		result = DNS_R_SIGINVALID;
		msg->sig0status = dns_tsigerror_badtime;
		goto failure;
	}

	isc_stdtime_get(&now);
	if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
		result = DNS_R_SIGFUTURE;
		msg->sig0status = dns_tsigerror_badtime;
		goto failure;
	}
	else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
		result = DNS_R_SIGEXPIRED;
		msg->sig0status = dns_tsigerror_badtime;
		goto failure;
	}

	if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
		result = DNS_R_SIGINVALID;
		msg->sig0status = dns_tsigerror_badkey;
		goto failure;
	}

	RETERR(dst_context_create(key, mctx, &ctx));

	/*
 	 * Digest the SIG(0) record, except for the signature.
	 */
	dns_rdata_toregion(&rdata, &r);
	r.length -= sig.siglen;
	RETERR(dst_context_adddata(ctx, &r));

	/*
	 * If this is a response, digest the query.
	 */
	if (is_response(msg))
		RETERR(dst_context_adddata(ctx, &msg->query));

	/*
	 * Extract the header.
	 */
	memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);

	/*
	 * Decrement the additional field counter.
	 */
	memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
	addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
	memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);

	/*
	 * Digest the modified header.
	 */
	header_r.base = (unsigned char *) header;
	header_r.length = DNS_MESSAGE_HEADERLEN;
	RETERR(dst_context_adddata(ctx, &header_r));

	/*
	 * Digest all non-SIG(0) records.
	 */
	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
	r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
	RETERR(dst_context_adddata(ctx, &r));

	sig_r.base = sig.signature;
	sig_r.length = sig.siglen;
	result = dst_context_verify(ctx, &sig_r);
	if (result != ISC_R_SUCCESS) {
		msg->sig0status = dns_tsigerror_badsig;
		goto failure;
	}

	msg->verified_sig = 1;

	dst_context_destroy(&ctx);
	dns_rdata_freestruct(&sig);

	return (ISC_R_SUCCESS);

failure:
	if (signeedsfree)
		dns_rdata_freestruct(&sig);
	if (ctx != NULL)
		dst_context_destroy(&ctx);

	return (result);
}
Beispiel #10
0
isc_result_t
dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
	dns_rdata_sig_t sig;	/* SIG(0) */
	unsigned char data[512];
	unsigned char header[DNS_MESSAGE_HEADERLEN];
	isc_buffer_t headerbuf, databuf, sigbuf;
	unsigned int sigsize;
	isc_buffer_t *dynbuf = NULL;
	dns_rdata_t *rdata;
	dns_rdatalist_t *datalist;
	dns_rdataset_t *dataset;
	isc_region_t r;
	isc_stdtime_t now;
	dst_context_t *ctx = NULL;
	isc_mem_t *mctx;
	isc_result_t result;
	isc_boolean_t signeedsfree = ISC_TRUE;

	REQUIRE(msg != NULL);
	REQUIRE(key != NULL);

	if (is_response(msg))
		REQUIRE(msg->query.base != NULL);

	mctx = msg->mctx;

	memset(&sig, 0, sizeof(sig));

	sig.mctx = mctx;
	sig.common.rdclass = dns_rdataclass_any;
	sig.common.rdtype = dns_rdatatype_sig;	/* SIG(0) */
	ISC_LINK_INIT(&sig.common, link);

	sig.covered = 0;
	sig.algorithm = dst_key_alg(key);
	sig.labels = 0; /* the root name */
	sig.originalttl = 0;

	isc_stdtime_get(&now);
	sig.timesigned = now - DNS_TSIG_FUDGE;
	sig.timeexpire = now + DNS_TSIG_FUDGE;

	sig.keyid = dst_key_id(key);

	dns_name_init(&sig.signer, NULL);
	dns_name_clone(dst_key_name(key), &sig.signer);

	sig.siglen = 0;
	sig.signature = NULL;

	isc_buffer_init(&databuf, data, sizeof(data));

	RETERR(dst_context_create(key, mctx, &ctx));

	/*
	 * Digest the fields of the SIG - we can cheat and use
	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
	 * is identical to dns format.
	 */
	RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
				    dns_rdatatype_sig /* SIG(0) */,
				    &sig, &databuf));
	isc_buffer_usedregion(&databuf, &r);
	RETERR(dst_context_adddata(ctx, &r));

	/*
	 * If this is a response, digest the query.
	 */
	if (is_response(msg))
		RETERR(dst_context_adddata(ctx, &msg->query));

	/*
	 * Digest the header.
	 */
	isc_buffer_init(&headerbuf, header, sizeof(header));
	dns_message_renderheader(msg, &headerbuf);
	isc_buffer_usedregion(&headerbuf, &r);
	RETERR(dst_context_adddata(ctx, &r));

	/*
	 * Digest the remainder of the message.
	 */
	isc_buffer_usedregion(msg->buffer, &r);
	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
	RETERR(dst_context_adddata(ctx, &r));

	RETERR(dst_key_sigsize(key, &sigsize));
	sig.siglen = sigsize;
	sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
	if (sig.signature == NULL) {
		result = ISC_R_NOMEMORY;
		goto failure;
	}

	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
	RETERR(dst_context_sign(ctx, &sigbuf));
	dst_context_destroy(&ctx);

	rdata = NULL;
	RETERR(dns_message_gettemprdata(msg, &rdata));
	RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
	RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
				    dns_rdatatype_sig /* SIG(0) */,
				    &sig, dynbuf));

	isc_mem_put(mctx, sig.signature, sig.siglen);
	signeedsfree = ISC_FALSE;

	dns_message_takebuffer(msg, &dynbuf);

	datalist = NULL;
	RETERR(dns_message_gettemprdatalist(msg, &datalist));
	datalist->rdclass = dns_rdataclass_any;
	datalist->type = dns_rdatatype_sig;	/* SIG(0) */
	datalist->covers = 0;
	datalist->ttl = 0;
	ISC_LIST_INIT(datalist->rdata);
	ISC_LIST_APPEND(datalist->rdata, rdata, link);
	dataset = NULL;
	RETERR(dns_message_gettemprdataset(msg, &dataset));
	dns_rdataset_init(dataset);
	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
	msg->sig0 = dataset;

	return (ISC_R_SUCCESS);

failure:
	if (dynbuf != NULL)
		isc_buffer_free(&dynbuf);
	if (signeedsfree)
		isc_mem_put(mctx, sig.signature, sig.siglen);
	if (ctx != NULL)
		dst_context_destroy(&ctx);

	return (result);
}
Beispiel #11
0
isc_result_t
dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
			 dns_dbnode_t *node, dns_name_t *name,
			 const char *directory, isc_mem_t *mctx,
			 unsigned int maxkeys, dst_key_t **keys,
			 unsigned int *nkeys)
{
	dns_rdataset_t rdataset;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_result_t result;
	dst_key_t *pubkey = NULL;
	unsigned int count = 0;

	REQUIRE(nkeys != NULL);
	REQUIRE(keys != NULL);

	*nkeys = 0;
	dns_rdataset_init(&rdataset);
	RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
				   &rdataset, NULL));
	RETERR(dns_rdataset_first(&rdataset));
	while (result == ISC_R_SUCCESS && count < maxkeys) {
		pubkey = NULL;
		dns_rdataset_current(&rdataset, &rdata);
		RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
		if (!is_zone_key(pubkey) ||
		    (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
			goto next;
		keys[count] = NULL;
		result = dst_key_fromfile(dst_key_name(pubkey),
					  dst_key_id(pubkey),
					  dst_key_alg(pubkey),
					  DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
					  directory,
					  mctx, &keys[count]);
		if (result == ISC_R_FILENOTFOUND) {
			keys[count] = pubkey;
			pubkey = NULL;
			count++;
			goto next;
		}
		if (result != ISC_R_SUCCESS)
			goto failure;
		if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
			/* We should never get here. */
			dst_key_free(&keys[count]);
			goto next;
		}
		count++;
 next:
		if (pubkey != NULL)
			dst_key_free(&pubkey);
		dns_rdata_reset(&rdata);
		result = dns_rdataset_next(&rdataset);
	}
	if (result != ISC_R_NOMORE)
		goto failure;
	if (count == 0)
		result = ISC_R_NOTFOUND;
	else
		result = ISC_R_SUCCESS;

 failure:
	if (dns_rdataset_isassociated(&rdataset))
		dns_rdataset_disassociate(&rdataset);
	if (pubkey != NULL)
		dst_key_free(&pubkey);
	if (result != ISC_R_SUCCESS)
		while (count > 0)
			dst_key_free(&keys[--count]);
	*nkeys = count;
	return (result);
}
Beispiel #12
0
isc_result_t
dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
		isc_stdtime_t *inception, isc_stdtime_t *expire,
		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
{
	dns_rdata_rrsig_t sig;
	dns_rdata_t tmpsigrdata;
	dns_rdata_t *rdatas;
	int nrdatas, i;
	isc_buffer_t sigbuf, envbuf;
	isc_region_t r;
	dst_context_t *ctx = NULL;
	isc_result_t ret;
	isc_buffer_t *databuf = NULL;
	char data[256 + 8];
	isc_uint32_t flags;
	unsigned int sigsize;
	dns_fixedname_t fnewname;

	REQUIRE(name != NULL);
	REQUIRE(dns_name_countlabels(name) <= 255);
	REQUIRE(set != NULL);
	REQUIRE(key != NULL);
	REQUIRE(inception != NULL);
	REQUIRE(expire != NULL);
	REQUIRE(mctx != NULL);
	REQUIRE(sigrdata != NULL);

	if (*inception >= *expire)
		return (DNS_R_INVALIDTIME);

	/*
	 * Is the key allowed to sign data?
	 */
	flags = dst_key_flags(key);
	if (flags & DNS_KEYTYPE_NOAUTH)
		return (DNS_R_KEYUNAUTHORIZED);
	if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
		return (DNS_R_KEYUNAUTHORIZED);

	sig.mctx = mctx;
	sig.common.rdclass = set->rdclass;
	sig.common.rdtype = dns_rdatatype_rrsig;
	ISC_LINK_INIT(&sig.common, link);

	dns_name_init(&sig.signer, NULL);
	dns_name_clone(dst_key_name(key), &sig.signer);

	sig.covered = set->type;
	sig.algorithm = dst_key_alg(key);
	sig.labels = dns_name_countlabels(name) - 1;
	if (dns_name_iswildcard(name))
		sig.labels--;
	sig.originalttl = set->ttl;
	sig.timesigned = *inception;
	sig.timeexpire = *expire;
	sig.keyid = dst_key_id(key);
	ret = dst_key_sigsize(key, &sigsize);
	if (ret != ISC_R_SUCCESS)
		return (ret);
	sig.siglen = sigsize;
	/*
	 * The actual contents of sig.signature are not important yet, since
	 * they're not used in digest_sig().
	 */
	sig.signature = isc_mem_get(mctx, sig.siglen);
	if (sig.signature == NULL)
		return (ISC_R_NOMEMORY);

	ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_signature;

	dns_rdata_init(&tmpsigrdata);
	ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
				   sig.common.rdtype, &sig, databuf);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_databuf;

	ret = dst_context_create(key, mctx, &ctx);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_databuf;

	/*
	 * Digest the SIG rdata.
	 */
	ret = digest_sig(ctx, &tmpsigrdata, &sig);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_context;

	dns_fixedname_init(&fnewname);
	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
					NULL) == ISC_R_SUCCESS);
	dns_name_toregion(dns_fixedname_name(&fnewname), &r);

	/*
	 * Create an envelope for each rdata: <name|type|class|ttl>.
	 */
	isc_buffer_init(&envbuf, data, sizeof(data));
	memcpy(data, r.base, r.length);
	isc_buffer_add(&envbuf, r.length);
	isc_buffer_putuint16(&envbuf, set->type);
	isc_buffer_putuint16(&envbuf, set->rdclass);
	isc_buffer_putuint32(&envbuf, set->ttl);

	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_context;
	isc_buffer_usedregion(&envbuf, &r);

	for (i = 0; i < nrdatas; i++) {
		isc_uint16_t len;
		isc_buffer_t lenbuf;
		isc_region_t lenr;

		/*
		 * Skip duplicates.
		 */
		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
		    continue;

		/*
		 * Digest the envelope.
		 */
		ret = dst_context_adddata(ctx, &r);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_array;

		/*
		 * Digest the length of the rdata.
		 */
		isc_buffer_init(&lenbuf, &len, sizeof(len));
		INSIST(rdatas[i].length < 65536);
		isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
		isc_buffer_usedregion(&lenbuf, &lenr);
		ret = dst_context_adddata(ctx, &lenr);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_array;

		/*
		 * Digest the rdata.
		 */
		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
		if (ret != ISC_R_SUCCESS)
			goto cleanup_array;
	}

	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
	ret = dst_context_sign(ctx, &sigbuf);
	if (ret != ISC_R_SUCCESS)
		goto cleanup_array;
	isc_buffer_usedregion(&sigbuf, &r);
	if (r.length != sig.siglen) {
		ret = ISC_R_NOSPACE;
		goto cleanup_array;
	}
	memcpy(sig.signature, r.base, sig.siglen);

	ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
				  sig.common.rdtype, &sig, buffer);

cleanup_array:
	isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
cleanup_context:
	dst_context_destroy(&ctx);
cleanup_databuf:
	isc_buffer_free(&databuf);
cleanup_signature:
	isc_mem_put(mctx, sig.signature, sig.siglen);

	return (ret);
}
Beispiel #13
0
int
main(int argc, char **argv) {
	char *keyname;
	isc_taskmgr_t *taskmgr;
	isc_timermgr_t *timermgr;
	isc_socketmgr_t *socketmgr;
	isc_socket_t *sock;
	unsigned int attrs, attrmask;
	isc_sockaddr_t bind_any;
	dns_dispatchmgr_t *dispatchmgr;
	dns_dispatch_t *dispatchv4;
	dns_view_t *view;
	isc_entropy_t *ectx;
	dns_tkeyctx_t *tctx;
	dst_key_t *dstkey;
	isc_log_t *log;
	isc_logconfig_t *logconfig;
	isc_task_t *task;
	isc_result_t result;
	int type;

	RUNCHECK(isc_app_start());

	if (argc < 2) {
		fprintf(stderr, "I:no key to delete\n");
		exit(-1);
	}
	keyname = argv[1];

	dns_result_register();

	mctx = NULL;
	RUNCHECK(isc_mem_create(0, 0, &mctx));

	ectx = NULL;
	RUNCHECK(isc_entropy_create(mctx, &ectx));
	RUNCHECK(isc_entropy_createfilesource(ectx, "random.data"));
	RUNCHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE));

	log = NULL;
	logconfig = NULL;
	RUNCHECK(isc_log_create(mctx, &log, &logconfig));

	RUNCHECK(dst_lib_init(mctx, ectx, ISC_ENTROPY_GOODONLY));

	taskmgr = NULL;
	RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
	task = NULL;
	RUNCHECK(isc_task_create(taskmgr, 0, &task));
	timermgr = NULL;
	RUNCHECK(isc_timermgr_create(mctx, &timermgr));
	socketmgr = NULL;
	RUNCHECK(isc_socketmgr_create(mctx, &socketmgr));
	dispatchmgr = NULL;
	RUNCHECK(dns_dispatchmgr_create(mctx, NULL, &dispatchmgr));
	isc_sockaddr_any(&bind_any);
	attrs = DNS_DISPATCHATTR_UDP |
		DNS_DISPATCHATTR_MAKEQUERY |
		DNS_DISPATCHATTR_IPV4;
	attrmask = DNS_DISPATCHATTR_UDP |
		   DNS_DISPATCHATTR_TCP |
		   DNS_DISPATCHATTR_IPV4 |
		   DNS_DISPATCHATTR_IPV6;
	dispatchv4 = NULL;
	RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
					  &bind_any, 4096, 4, 2, 3, 5,
					  attrs, attrmask, &dispatchv4));
	requestmgr = NULL;
	RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr,
					    dispatchmgr, dispatchv4, NULL,
					    &requestmgr));

	ring = NULL;
	RUNCHECK(dns_tsigkeyring_create(mctx, &ring));
	tctx = NULL;
	RUNCHECK(dns_tkeyctx_create(mctx, ectx, &tctx));

	view = NULL;
	RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
	dns_view_setkeyring(view, ring);

	sock = NULL;
	RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp,
				   &sock));

	RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL));

	dstkey = NULL;
	type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY;
	result = dst_key_fromnamedfile(keyname, NULL, type, mctx, &dstkey);
	CHECK("dst_key_fromnamedfile", result);
	result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
					   DNS_TSIG_HMACMD5_NAME,
					   dstkey, ISC_TRUE, NULL, 0, 0,
					   mctx, ring, &tsigkey);
	dst_key_free(&dstkey);
	CHECK("dns_tsigkey_createfromkey", result);

	(void)isc_app_run();

	dns_requestmgr_shutdown(requestmgr);
	dns_requestmgr_detach(&requestmgr);
	dns_dispatch_detach(&dispatchv4);
	dns_dispatchmgr_destroy(&dispatchmgr);
	isc_task_shutdown(task);
	isc_task_detach(&task);
	isc_taskmgr_destroy(&taskmgr);
	isc_socket_detach(&sock);
	isc_socketmgr_destroy(&socketmgr);
	isc_timermgr_destroy(&timermgr);

	dns_tsigkeyring_detach(&ring);

	dns_tsigkey_detach(&tsigkey);

	dns_tkeyctx_destroy(&tctx);

	dns_view_detach(&view);

	isc_log_destroy(&log);

	dst_lib_destroy();
	isc_hash_destroy();
	isc_entropy_detach(&ectx);

	isc_mem_destroy(&mctx);

	isc_app_finish();

	return (0);
}
Beispiel #14
0
int
main(int argc, char **argv) {
	isc_result_t	result;
#ifdef USE_PKCS11
	const char	*engine = "pkcs11";
#else
	const char	*engine = NULL;
#endif
	char		*filename = NULL, *directory = NULL;
	char		newname[1024];
	char		keystr[DST_KEY_FORMATSIZE];
	char		*endp, *p;
	int		ch;
	isc_entropy_t	*ectx = NULL;
	const char	*predecessor = NULL;
	dst_key_t	*prevkey = NULL;
	dst_key_t	*key = NULL;
	isc_buffer_t	buf;
	dns_name_t	*name = NULL;
	dns_secalg_t 	alg = 0;
	unsigned int 	size = 0;
	isc_uint16_t	flags = 0;
	int		prepub = -1;
	dns_ttl_t	ttl = 0;
	isc_stdtime_t	now;
	isc_stdtime_t	pub = 0, act = 0, rev = 0, inact = 0, del = 0;
	isc_boolean_t	setpub = ISC_FALSE, setact = ISC_FALSE;
	isc_boolean_t	setrev = ISC_FALSE, setinact = ISC_FALSE;
	isc_boolean_t	setdel = ISC_FALSE, setttl = ISC_FALSE;
	isc_boolean_t	unsetpub = ISC_FALSE, unsetact = ISC_FALSE;
	isc_boolean_t	unsetrev = ISC_FALSE, unsetinact = ISC_FALSE;
	isc_boolean_t	unsetdel = ISC_FALSE;
	isc_boolean_t	printcreate = ISC_FALSE, printpub = ISC_FALSE;
	isc_boolean_t	printact = ISC_FALSE,  printrev = ISC_FALSE;
	isc_boolean_t	printinact = ISC_FALSE, printdel = ISC_FALSE;
	isc_boolean_t	force = ISC_FALSE;
	isc_boolean_t   epoch = ISC_FALSE;
	isc_boolean_t   changed = ISC_FALSE;
	isc_log_t       *log = NULL;

	isc__mem_register();
	if (argc == 1)
		usage();

	result = isc_mem_create(0, 0, &mctx);
	if (result != ISC_R_SUCCESS)
		fatal("Out of memory");

	setup_logging(verbose, mctx, &log);

	dns_result_register();

	isc_commandline_errprint = ISC_FALSE;

	isc_stdtime_get(&now);

#define CMDLINE_FLAGS "A:D:E:fhI:i:K:L:P:p:R:S:uv:"
	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
		switch (ch) {
		case 'E':
			engine = isc_commandline_argument;
			break;
		case 'f':
			force = ISC_TRUE;
			break;
		case 'p':
			p = isc_commandline_argument;
			if (!strcasecmp(p, "all")) {
				printcreate = ISC_TRUE;
				printpub = ISC_TRUE;
				printact = ISC_TRUE;
				printrev = ISC_TRUE;
				printinact = ISC_TRUE;
				printdel = ISC_TRUE;
				break;
			}

			do {
				switch (*p++) {
				case 'C':
					printcreate = ISC_TRUE;
					break;
				case 'P':
					printpub = ISC_TRUE;
					break;
				case 'A':
					printact = ISC_TRUE;
					break;
				case 'R':
					printrev = ISC_TRUE;
					break;
				case 'I':
					printinact = ISC_TRUE;
					break;
				case 'D':
					printdel = ISC_TRUE;
					break;
				case ' ':
					break;
				default:
					usage();
					break;
				}
			} while (*p != '\0');
			break;
		case 'u':
			epoch = ISC_TRUE;
			break;
		case 'K':
			/*
			 * We don't have to copy it here, but do it to
			 * simplify cleanup later
			 */
			directory = isc_mem_strdup(mctx,
						   isc_commandline_argument);
			if (directory == NULL) {
				fatal("Failed to allocate memory for "
				      "directory");
			}
			break;
		case 'L':
			if (strcmp(isc_commandline_argument, "none") == 0)
				ttl = 0;
			else
				ttl = strtottl(isc_commandline_argument);
			setttl = ISC_TRUE;
			break;
		case 'v':
			verbose = strtol(isc_commandline_argument, &endp, 0);
			if (*endp != '\0')
				fatal("-v must be followed by a number");
			break;
		case 'P':
			if (setpub || unsetpub)
				fatal("-P specified more than once");

			changed = ISC_TRUE;
			if (!strcasecmp(isc_commandline_argument, "none")) {
				unsetpub = ISC_TRUE;
			} else {
				setpub = ISC_TRUE;
				pub = strtotime(isc_commandline_argument,
						now, now);
			}
			break;
		case 'A':
			if (setact || unsetact)
				fatal("-A specified more than once");

			changed = ISC_TRUE;
			if (!strcasecmp(isc_commandline_argument, "none")) {
				unsetact = ISC_TRUE;
			} else {
				setact = ISC_TRUE;
				act = strtotime(isc_commandline_argument,
						now, now);
			}
			break;
		case 'R':
			if (setrev || unsetrev)
				fatal("-R specified more than once");

			changed = ISC_TRUE;
			if (!strcasecmp(isc_commandline_argument, "none")) {
				unsetrev = ISC_TRUE;
			} else {
				setrev = ISC_TRUE;
				rev = strtotime(isc_commandline_argument,
						now, now);
			}
			break;
		case 'I':
			if (setinact || unsetinact)
				fatal("-I specified more than once");

			changed = ISC_TRUE;
			if (!strcasecmp(isc_commandline_argument, "none")) {
				unsetinact = ISC_TRUE;
			} else {
				setinact = ISC_TRUE;
				inact = strtotime(isc_commandline_argument,
						now, now);
			}
			break;
		case 'D':
			if (setdel || unsetdel)
				fatal("-D specified more than once");

			changed = ISC_TRUE;
			if (!strcasecmp(isc_commandline_argument, "none")) {
				unsetdel = ISC_TRUE;
			} else {
				setdel = ISC_TRUE;
				del = strtotime(isc_commandline_argument,
						now, now);
			}
			break;
		case 'S':
			predecessor = isc_commandline_argument;
			break;
		case 'i':
			prepub = strtottl(isc_commandline_argument);
			break;
		case '?':
			if (isc_commandline_option != '?')
				fprintf(stderr, "%s: invalid argument -%c\n",
					program, isc_commandline_option);
			/* Falls into */
		case 'h':
			usage();

		default:
			fprintf(stderr, "%s: unhandled option -%c\n",
				program, isc_commandline_option);
			exit(1);
		}
	}

	if (argc < isc_commandline_index + 1 ||
	    argv[isc_commandline_index] == NULL)
		fatal("The key file name was not specified");
	if (argc > isc_commandline_index + 1)
		fatal("Extraneous arguments");

	if (ectx == NULL)
		setup_entropy(mctx, NULL, &ectx);
	result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
	if (result != ISC_R_SUCCESS)
		fatal("Could not initialize hash");
	result = dst_lib_init2(mctx, ectx, engine,
			       ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
	if (result != ISC_R_SUCCESS)
		fatal("Could not initialize dst: %s",
		      isc_result_totext(result));
	isc_entropy_stopcallbacksources(ectx);

	if (predecessor != NULL) {
		char keystr[DST_KEY_FORMATSIZE];
		isc_stdtime_t when;
		int major, minor;

		if (prepub == -1)
			prepub = (30 * 86400);

		if (setpub || unsetpub)
			fatal("-S and -P cannot be used together");
		if (setact || unsetact)
			fatal("-S and -A cannot be used together");

		result = dst_key_fromnamedfile(predecessor, directory,
					       DST_TYPE_PUBLIC |
					       DST_TYPE_PRIVATE,
					       mctx, &prevkey);
		if (result != ISC_R_SUCCESS)
			fatal("Invalid keyfile %s: %s",
			      filename, isc_result_totext(result));
		if (!dst_key_isprivate(prevkey))
			fatal("%s is not a private key", filename);

		name = dst_key_name(prevkey);
		alg = dst_key_alg(prevkey);
		size = dst_key_size(prevkey);
		flags = dst_key_flags(prevkey);

		dst_key_format(prevkey, keystr, sizeof(keystr));
		dst_key_getprivateformat(prevkey, &major, &minor);
		if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION)
			fatal("Predecessor has incompatible format "
			      "version %d.%d\n\t", major, minor);

		result = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when);
		if (result != ISC_R_SUCCESS)
			fatal("Predecessor has no activation date. "
			      "You must set one before\n\t"
			      "generating a successor.");

		result = dst_key_gettime(prevkey, DST_TIME_INACTIVE, &act);
		if (result != ISC_R_SUCCESS)
			fatal("Predecessor has no inactivation date. "
			      "You must set one before\n\t"
			      "generating a successor.");

		pub = act - prepub;
		if (pub < now && prepub != 0)
			fatal("Predecessor will become inactive before the\n\t"
			      "prepublication period ends.  Either change "
			      "its inactivation date,\n\t"
			      "or use the -i option to set a shorter "
			      "prepublication interval.");

		result = dst_key_gettime(prevkey, DST_TIME_DELETE, &when);
		if (result != ISC_R_SUCCESS)
			fprintf(stderr, "%s: WARNING: Predecessor has no "
					"removal date;\n\t"
					"it will remain in the zone "
					"indefinitely after rollover.\n",
					program);

		changed = setpub = setact = ISC_TRUE;
		dst_key_free(&prevkey);
	} else {
		if (prepub < 0)
			prepub = 0;

		if (prepub > 0) {
			if (setpub && setact && (act - prepub) < pub)
				fatal("Activation and publication dates "
				      "are closer together than the\n\t"
				      "prepublication interval.");

			if (setpub && !setact) {
				setact = ISC_TRUE;
				act = pub + prepub;
			} else if (setact && !setpub) {
				setpub = ISC_TRUE;
				pub = act - prepub;
			}

			if ((act - prepub) < now)
				fatal("Time until activation is shorter "
				      "than the\n\tprepublication interval.");
		}
	}

	if (directory != NULL) {
		filename = argv[isc_commandline_index];
	} else {
		result = isc_file_splitpath(mctx, argv[isc_commandline_index],
					    &directory, &filename);
		if (result != ISC_R_SUCCESS)
			fatal("cannot process filename %s: %s",
			      argv[isc_commandline_index],
			      isc_result_totext(result));
	}

	result = dst_key_fromnamedfile(filename, directory,
				       DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
				       mctx, &key);
	if (result != ISC_R_SUCCESS)
		fatal("Invalid keyfile %s: %s",
		      filename, isc_result_totext(result));

	if (!dst_key_isprivate(key))
		fatal("%s is not a private key", filename);

	dst_key_format(key, keystr, sizeof(keystr));

	if (predecessor != NULL) {
		if (!dns_name_equal(name, dst_key_name(key)))
			fatal("Key name mismatch");
		if (alg != dst_key_alg(key))
			fatal("Key algorithm mismatch");
		if (size != dst_key_size(key))
			fatal("Key size mismatch");
		if (flags != dst_key_flags(key))
			fatal("Key flags mismatch");
	}

	if (force)
		set_keyversion(key);
	else
		check_keyversion(key, keystr);

	if (verbose > 2)
		fprintf(stderr, "%s: %s\n", program, keystr);

	/*
	 * Set time values.
	 */
	if (setpub)
		dst_key_settime(key, DST_TIME_PUBLISH, pub);
	else if (unsetpub)
		dst_key_unsettime(key, DST_TIME_PUBLISH);

	if (setact)
		dst_key_settime(key, DST_TIME_ACTIVATE, act);
	else if (unsetact)
		dst_key_unsettime(key, DST_TIME_ACTIVATE);

	if (setrev) {
		if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0)
			fprintf(stderr, "%s: warning: Key %s is already "
					"revoked; changing the revocation date "
					"will not affect this.\n",
					program, keystr);
		if ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0)
			fprintf(stderr, "%s: warning: Key %s is not flagged as "
					"a KSK, but -R was used.  Revoking a "
					"ZSK is legal, but undefined.\n",
					program, keystr);
		dst_key_settime(key, DST_TIME_REVOKE, rev);
	} else if (unsetrev) {
		if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0)
			fprintf(stderr, "%s: warning: Key %s is already "
					"revoked; removing the revocation date "
					"will not affect this.\n",
					program, keystr);
		dst_key_unsettime(key, DST_TIME_REVOKE);
	}

	if (setinact)
		dst_key_settime(key, DST_TIME_INACTIVE, inact);
	else if (unsetinact)
		dst_key_unsettime(key, DST_TIME_INACTIVE);

	if (setdel)
		dst_key_settime(key, DST_TIME_DELETE, del);
	else if (unsetdel)
		dst_key_unsettime(key, DST_TIME_DELETE);

	if (setttl)
		dst_key_setttl(key, ttl);

	/*
	 * No metadata changes were made but we're forcing an upgrade
	 * to the new format anyway: use "-P now -A now" as the default
	 */
	if (force && !changed) {
		dst_key_settime(key, DST_TIME_PUBLISH, now);
		dst_key_settime(key, DST_TIME_ACTIVATE, now);
		changed = ISC_TRUE;
	}

	if (!changed && setttl)
		changed = ISC_TRUE;

	/*
	 * Print out time values, if -p was used.
	 */
	if (printcreate)
		printtime(key, DST_TIME_CREATED, "Created", epoch, stdout);

	if (printpub)
		printtime(key, DST_TIME_PUBLISH, "Publish", epoch, stdout);

	if (printact)
		printtime(key, DST_TIME_ACTIVATE, "Activate", epoch, stdout);

	if (printrev)
		printtime(key, DST_TIME_REVOKE, "Revoke", epoch, stdout);

	if (printinact)
		printtime(key, DST_TIME_INACTIVE, "Inactive", epoch, stdout);

	if (printdel)
		printtime(key, DST_TIME_DELETE, "Delete", epoch, stdout);

	if (changed) {
		isc_buffer_init(&buf, newname, sizeof(newname));
		result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory,
					       &buf);
		if (result != ISC_R_SUCCESS) {
			fatal("Failed to build public key filename: %s",
			      isc_result_totext(result));
		}

		result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
					directory);
		if (result != ISC_R_SUCCESS) {
			dst_key_format(key, keystr, sizeof(keystr));
			fatal("Failed to write key %s: %s", keystr,
			      isc_result_totext(result));
		}

		printf("%s\n", newname);

		isc_buffer_clear(&buf);
		result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory,
					       &buf);
		if (result != ISC_R_SUCCESS) {
			fatal("Failed to build private key filename: %s",
			      isc_result_totext(result));
		}
		printf("%s\n", newname);
	}

	dst_key_free(&key);
	dst_lib_destroy();
	isc_hash_destroy();
	cleanup_entropy(&ectx);
	if (verbose > 10)
		isc_mem_stats(mctx, stdout);
	cleanup_logging(&log);
	isc_mem_free(mctx, directory);
	isc_mem_destroy(&mctx);

	return (0);
}
int
main(int argc, char *argv[]) {
	int i, ch;
	char *startstr = NULL, *endstr = NULL;
	dns_fixedname_t fdomain;
	dns_name_t *domain = NULL;
	char *output = NULL;
	char *endp;
	unsigned char data[65536];
	dns_db_t *db;
	dns_dbversion_t *version;
	dns_diff_t diff;
	dns_difftuple_t *tuple;
	dns_fixedname_t tname;
	dst_key_t *key = NULL;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	dns_rdataset_t rdataset;
	dns_rdataclass_t rdclass;
	isc_result_t result;
	isc_buffer_t b;
	isc_region_t r;
	isc_log_t *log = NULL;
	keynode_t *keynode;
	unsigned int eflags;
	isc_boolean_t pseudorandom = ISC_FALSE;
	isc_boolean_t tryverify = ISC_FALSE;

	result = isc_mem_create(0, 0, &mctx);
	if (result != ISC_R_SUCCESS)
		fatal("failed to create memory context: %s",
		      isc_result_totext(result));

	dns_result_register();

	while ((ch = isc_commandline_parse(argc, argv, "as:e:t:r:v:ph")) != -1)
	{
		switch (ch) {
		case 'a':
			tryverify = ISC_TRUE;
			break;
		case 's':
			startstr = isc_commandline_argument;
			break;

		case 'e':
			endstr = isc_commandline_argument;
			break;

		case 't':
			endp = NULL;
			ttl = strtol(isc_commandline_argument, &endp, 0);
			if (*endp != '\0')
				fatal("TTL must be numeric");
			break;

		case 'r':
			setup_entropy(mctx, isc_commandline_argument, &ectx);
			break;

		case 'v':
			endp = NULL;
			verbose = strtol(isc_commandline_argument, &endp, 0);
			if (*endp != '\0')
				fatal("verbose level must be numeric");
			break;

		case 'p':
			pseudorandom = ISC_TRUE;
			break;

		case 'h':
		default:
			usage();

		}
	}

	argc -= isc_commandline_index;
	argv += isc_commandline_index;

	if (argc < 1)
		usage();

	if (ectx == NULL)
		setup_entropy(mctx, NULL, &ectx);
	eflags = ISC_ENTROPY_BLOCKING;
	if (!pseudorandom)
		eflags |= ISC_ENTROPY_GOODONLY;
	result = dst_lib_init(mctx, ectx, eflags);
	if (result != ISC_R_SUCCESS)
		fatal("could not initialize dst: %s", 
		      isc_result_totext(result));

	isc_stdtime_get(&now);

	if (startstr != NULL)
		starttime = strtotime(startstr, now, now);
	else
		starttime = now;

	if (endstr != NULL)
		endtime = strtotime(endstr, now, starttime);
	else
		endtime = starttime + (30 * 24 * 60 * 60);

	if (ttl == -1) {
		ttl = 3600;
		fprintf(stderr, "%s: TTL not specified, assuming 3600\n",
			program);
	}

	setup_logging(verbose, mctx, &log);

	dns_diff_init(mctx, &diff);
	rdclass = 0;

	ISC_LIST_INIT(keylist);

	for (i = 0; i < argc; i++) {
		char namestr[DNS_NAME_FORMATSIZE];
		isc_buffer_t namebuf;

		key = NULL;
		result = dst_key_fromnamedfile(argv[i], DST_TYPE_PUBLIC,
					       mctx, &key);
		if (result != ISC_R_SUCCESS)
			fatal("error loading key from %s: %s", argv[i],
			      isc_result_totext(result));
		if (rdclass == 0)
			rdclass = dst_key_class(key);

		isc_buffer_init(&namebuf, namestr, sizeof(namestr));
		result = dns_name_tofilenametext(dst_key_name(key),
						 ISC_FALSE,
						 &namebuf);
		check_result(result, "dns_name_tofilenametext");
		isc_buffer_putuint8(&namebuf, 0);

		if (domain == NULL) {
			dns_fixedname_init(&fdomain);
			domain = dns_fixedname_name(&fdomain);
			dns_name_copy(dst_key_name(key), domain, NULL);
		} else if (!dns_name_equal(domain, dst_key_name(key))) {
			char str[DNS_NAME_FORMATSIZE];
			dns_name_format(domain, str, sizeof(str));
			fatal("all keys must have the same owner - %s "
			      "and %s do not match", str, namestr);
		}

		if (output == NULL) {
			output = isc_mem_allocate(mctx,
						  strlen("keyset-") +
						  strlen(namestr) + 1);
			if (output == NULL)
				fatal("out of memory");
			sprintf(output, "keyset-%s", namestr);
		}

		if (dst_key_iszonekey(key)) {
			dst_key_t *zonekey = NULL;
			result = dst_key_fromnamedfile(argv[i],
						       DST_TYPE_PUBLIC |
						       DST_TYPE_PRIVATE,
						       mctx, &zonekey);
			if (result != ISC_R_SUCCESS)
				fatal("failed to read private key %s: %s",
				      argv[i], isc_result_totext(result));
			if (!zonekey_on_list(zonekey)) {
				keynode = isc_mem_get(mctx, sizeof(keynode_t));
				if (keynode == NULL)
					fatal("out of memory");
				keynode->key = zonekey;
				ISC_LIST_INITANDAPPEND(keylist, keynode, link);
			} else
				dst_key_free(&zonekey);
		}
		dns_rdata_reset(&rdata);
		isc_buffer_init(&b, data, sizeof(data));
		result = dst_key_todns(key, &b);
		dst_key_free(&key);
		if (result != ISC_R_SUCCESS)
			fatal("failed to convert key %s to a DNS KEY: %s",
			      argv[i], isc_result_totext(result));
		isc_buffer_usedregion(&b, &r);
		dns_rdata_fromregion(&rdata, rdclass, dns_rdatatype_dnskey, &r);
		tuple = NULL;
		result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
					      domain, ttl, &rdata, &tuple);
		check_result(result, "dns_difftuple_create");
		dns_diff_append(&diff, &tuple);
	}

	db = NULL;
	result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
			       rdclass, 0, NULL, &db);
	if (result != ISC_R_SUCCESS)
		fatal("failed to create a database");

	version = NULL;
	dns_db_newversion(db, &version);

	result = dns_diff_apply(&diff, db, version);
	check_result(result, "dns_diff_apply");
	dns_diff_clear(&diff);

	dns_fixedname_init(&tname);
	dns_rdataset_init(&rdataset);
	result = dns_db_find(db, domain, version, dns_rdatatype_dnskey, 0, 0,
			     NULL, dns_fixedname_name(&tname), &rdataset,
			     NULL);
	check_result(result, "dns_db_find");

	if (ISC_LIST_EMPTY(keylist))
		fprintf(stderr,
			"%s: no private zone key found; not self-signing\n",
			program);
	for (keynode = ISC_LIST_HEAD(keylist);
	     keynode != NULL;
	     keynode = ISC_LIST_NEXT(keynode, link))
	{
		dns_rdata_reset(&rdata);
		isc_buffer_init(&b, data, sizeof(data));
		result = dns_dnssec_sign(domain, &rdataset, keynode->key,
					 &starttime, &endtime, mctx, &b,
					 &rdata);
		isc_entropy_stopcallbacksources(ectx);
		if (result != ISC_R_SUCCESS) {
			char keystr[KEY_FORMATSIZE];
			key_format(keynode->key, keystr, sizeof(keystr));
			fatal("failed to sign keyset with key %s: %s",
			      keystr, isc_result_totext(result));
		}
		if (tryverify) {
			result = dns_dnssec_verify(domain, &rdataset,
						   keynode->key, ISC_TRUE,
						   mctx, &rdata);
			if (result != ISC_R_SUCCESS) {
				char keystr[KEY_FORMATSIZE];
				key_format(keynode->key, keystr, sizeof(keystr));
				fatal("signature from key '%s' failed to "
				      "verify: %s",
				      keystr, isc_result_totext(result));
			}
		}
		tuple = NULL;
		result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
					      domain, ttl, &rdata, &tuple);
		check_result(result, "dns_difftuple_create");
		dns_diff_append(&diff, &tuple);
	}

	result = dns_diff_apply(&diff, db, version);
	check_result(result, "dns_diff_apply");
	dns_diff_clear(&diff);

	dns_rdataset_disassociate(&rdataset);

	dns_db_closeversion(db, &version, ISC_TRUE);
	result = dns_db_dump(db, version, output);
	if (result != ISC_R_SUCCESS) {
		char domainstr[DNS_NAME_FORMATSIZE];
		dns_name_format(domain, domainstr, sizeof(domainstr));
		fatal("failed to write database for %s to %s",
		      domainstr, output);
	}

	printf("%s\n", output);

	dns_db_detach(&db);

	while (!ISC_LIST_EMPTY(keylist)) {
		keynode = ISC_LIST_HEAD(keylist);
		ISC_LIST_UNLINK(keylist, keynode, link);
		dst_key_free(&keynode->key);
		isc_mem_put(mctx, keynode, sizeof(keynode_t));
	}

	cleanup_logging(&log);
	cleanup_entropy(&ectx);

	isc_mem_free(mctx, output);
	dst_lib_destroy();
	if (verbose > 10)
		isc_mem_stats(mctx, stdout);
	isc_mem_destroy(&mctx);
	return (0);
}