bind9/bin/tests/keysigner.c
2000-05-12 21:09:53 +00:00

365 lines
9.7 KiB
C

/*
* Copyright (C) 1999, 2000 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include <config.h>
#include <stdlib.h>
#include <isc/string.h>
#include <isc/commandline.h>
#include <isc/mem.h>
#include <isc/util.h>
#include <dns/db.h>
#include <dns/dnssec.h>
#include <dns/log.h>
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/result.h>
#define BUFSIZE 2048
typedef struct keynode keynode_t;
struct keynode {
dst_key_t *key;
isc_boolean_t verified;
ISC_LINK(keynode_t) link;
};
typedef ISC_LIST(keynode_t) keylist_t;
static isc_stdtime_t now;
static int verbose;
static isc_mem_t *mctx = NULL;
static keylist_t keylist;
static inline void
fatal(char *message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
static inline void
check_result(isc_result_t result, char *message) {
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "%s: %s\n", message,
isc_result_totext(result));
exit(1);
}
}
static void
usage() {
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\tkeysigner [options] keyset keys\n");
fprintf(stderr, "\n");
fprintf(stderr, "Options: (default value in parenthesis) \n");
fprintf(stderr, "\t-v level:\n");
fprintf(stderr, "\t\tverbose level (0)\n");
fprintf(stderr, "\n");
fprintf(stderr, "keyset:\n");
fprintf(stderr, "\tfile name of key set to be signed\n");
fprintf(stderr, "keys:\n");
fprintf(stderr, "\tname/id/alg:\t\t");
fprintf(stderr, "key matching name, keyid, algorithm\n");
exit(0);
}
static void
loadkeys(dns_name_t *name, dns_rdataset_t *rdataset) {
dst_key_t *key;
dns_rdata_t rdata;
keynode_t *keynode;
isc_result_t result;
ISC_LIST_INIT(keylist);
result = dns_rdataset_first(rdataset);
check_result(result, "dns_rdataset_first");
for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) {
dns_rdataset_current(rdataset, &rdata);
key = NULL;
result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &key);
if (result != ISC_R_SUCCESS)
continue;
if (!dst_key_iszonekey(key))
continue;
keynode = isc_mem_get(mctx, sizeof (keynode_t));
if (keynode == NULL)
check_result(ISC_R_NOMEMORY, "isc_mem_get()");
keynode->key = key;
keynode->verified = ISC_FALSE;
ISC_LINK_INIT(keynode, link);
ISC_LIST_APPEND(keylist, keynode, link);
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
check_result(result, "loadkeys()");
}
static dst_key_t *
findkey(dns_rdata_sig_t *sig) {
keynode_t *keynode;
for (keynode = ISC_LIST_HEAD(keylist);
keynode != NULL;
keynode = ISC_LIST_NEXT(keynode, link))
{
if (dst_key_id(keynode->key) == sig->keyid &&
dst_key_alg(keynode->key) == sig->algorithm) {
keynode->verified = ISC_TRUE;
return (keynode->key);
}
}
fatal("signature generated by non-zone or missing key");
return (NULL);
}
int
main(int argc, char *argv[]) {
int i, ch;
char tdomain[1025];
dns_fixedname_t fdomain;
dns_name_t *domain;
char *output = NULL;
char *endp;
unsigned char *data;
dns_db_t *db;
dns_dbnode_t *node;
dns_dbversion_t *version;
dst_key_t *key = NULL;
dns_rdata_t *rdata, sigrdata;
dns_rdatalist_t sigrdatalist;
dns_rdataset_t rdataset, sigrdataset, newsigrdataset;
dns_rdata_sig_t sig;
isc_result_t result;
isc_buffer_t b;
isc_region_t r;
isc_log_t *log = NULL;
isc_logconfig_t *logconfig;
keynode_t *keynode;
dns_result_register();
result = isc_mem_create(0, 0, &mctx);
check_result(result, "isc_mem_create()");
while ((ch = isc_commandline_parse(argc, argv, "v:")) != -1)
{
switch (ch) {
case 'v':
endp = NULL;
verbose = strtol(isc_commandline_argument, &endp, 0);
if (*endp != '\0')
check_result(ISC_R_FAILURE, "strtol()");
break;
default:
usage();
}
}
argc -= isc_commandline_index;
argv += isc_commandline_index;
if (argc < 2)
usage();
isc_stdtime_get(&now);
if (verbose > 0) {
RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig)
== ISC_R_SUCCESS);
isc_log_setcontext(log);
dns_log_init(log);
dns_log_setcontext(log);
RUNTIME_CHECK(isc_log_usechannel(logconfig, "default_stderr",
NULL, NULL) == ISC_R_SUCCESS);
}
if (strlen(argv[0]) < 8 ||
strcmp(argv[0] + strlen(argv[0]) - 7, ".keyset") != 0)
fatal("keyset file must end in .keyset");
dns_fixedname_init(&fdomain);
domain = dns_fixedname_name(&fdomain);
isc_buffer_init(&b, argv[0], strlen(argv[0]) - 7);
isc_buffer_add(&b, strlen(argv[0]) - 7);
result = dns_name_fromtext(domain, &b, dns_rootname, ISC_FALSE, NULL);
check_result(result, "dns_name_fromtext()");
isc_buffer_init(&b, tdomain, sizeof(tdomain) - 1);
result = dns_name_totext(domain, ISC_FALSE, &b);
check_result(result, "dns_name_totext()");
isc_buffer_usedregion(&b, &r);
tdomain[r.length] = 0;
output = isc_mem_allocate(mctx,
strlen(tdomain) + strlen("signedkey") + 1);
if (output == NULL)
check_result(ISC_R_FAILURE, "isc_mem_allocate()");
strcpy(output, tdomain);
strcat(output, "signedkey");
db = NULL;
result = dns_db_create(mctx, "rbt", domain, ISC_FALSE,
dns_rdataclass_in, 0, NULL, &db);
check_result(result, "dns_db_create()");
result = dns_db_load(db, argv[0]);
check_result(result, "dns_db_load()");
version = NULL;
dns_db_newversion(db, &version);
node = NULL;
result = dns_db_findnode(db, domain, ISC_FALSE, &node);
check_result(result, "dns_db_findnode()");
dns_rdataset_init(&rdataset);
dns_rdataset_init(&sigrdataset);
result = dns_db_findrdataset(db, node, version, dns_rdatatype_key, 0,
0, &rdataset, &sigrdataset);
check_result(result, "dns_db_findrdataset()");
loadkeys(domain, &rdataset);
result = dns_rdataset_first(&sigrdataset);
check_result(result, "dns_rdataset_first()");
do {
dns_rdataset_current(&sigrdataset, &sigrdata);
result = dns_rdata_tostruct(&sigrdata, &sig, mctx);
check_result(result, "dns_rdata_tostruct");
key = findkey(&sig);
result = dns_dnssec_verify(domain, &rdataset, key,
ISC_TRUE, mctx, &sigrdata);
check_result(result, "dns_dnssec_verify");
dns_rdata_freestruct(&sig);
result = dns_rdataset_next(&sigrdataset);
} while (result == ISC_R_SUCCESS);
for (keynode = ISC_LIST_HEAD(keylist);
keynode != NULL;
keynode = ISC_LIST_NEXT(keynode, link))
if (!keynode->verified)
fatal("Not all zone keys self signed the key set");
result = dns_rdataset_first(&sigrdataset);
check_result(result, "dns_rdataset_first()");
dns_rdataset_current(&sigrdataset, &sigrdata);
result = dns_rdata_tostruct(&sigrdata, &sig, mctx);
check_result(result, "dns_rdata_tostruct()");
dns_rdataset_disassociate(&sigrdataset);
argc -= 1;
argv += 1;
dns_rdatalist_init(&sigrdatalist);
sigrdatalist.rdclass = rdataset.rdclass;
sigrdatalist.type = dns_rdatatype_sig;
sigrdatalist.covers = dns_rdatatype_key;
sigrdatalist.ttl = rdataset.ttl;
for (i = 0; i < argc; i++) {
int id, alg;
char *namestr, *idstr = NULL, *algstr = NULL;
namestr = argv[i];
idstr = strchr(namestr, '/');
if (idstr == NULL)
usage();
*idstr++ = 0;
algstr = strchr(idstr, '/');
if (algstr == NULL)
usage();
*algstr++ = 0;
endp = NULL;
id = strtol(idstr, &endp, 10);
if (*endp != '\0')
check_result(ISC_R_FAILURE, "strtol");
endp = NULL;
alg = strtol(algstr, &endp, 10);
if (*endp != '\0')
check_result(ISC_R_FAILURE, "strtol");
key = NULL;
result = dst_key_fromfile(namestr, id, alg, DST_TYPE_PRIVATE,
mctx, &key);
check_result (result, "dst_key_fromfile()");
rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
if (rdata == NULL)
check_result(ISC_R_NOMEMORY, "isc_mem_get()");
data = isc_mem_get(mctx, BUFSIZE);
if (data == NULL)
check_result(ISC_R_NOMEMORY, "isc_mem_get()");
isc_buffer_init(&b, data, BUFSIZE);
result = dns_dnssec_sign(domain, &rdataset, key,
&sig.timesigned, &sig.timeexpire,
mctx, &b, rdata);
check_result (result, "dns_dnssec_sign()");
ISC_LIST_APPEND(sigrdatalist.rdata, rdata, link);
dst_key_free(key);
}
dns_rdataset_init(&newsigrdataset);
result = dns_rdatalist_tordataset(&sigrdatalist, &newsigrdataset);
check_result (result, "dns_rdatalist_tordataset()");
dns_db_addrdataset(db, node, version, 0, &newsigrdataset, 0, NULL);
check_result (result, "dns_db_addrdataset()");
dns_db_detachnode(db, &node);
dns_db_closeversion(db, &version, ISC_TRUE);
result = dns_db_dump(db, version, output);
check_result(result, "dns_db_dump()");
dns_rdataset_disassociate(&rdataset);
dns_rdataset_disassociate(&newsigrdataset);
dns_rdata_freestruct(&sig);
while (!ISC_LIST_EMPTY(sigrdatalist.rdata)) {
rdata = ISC_LIST_HEAD(sigrdatalist.rdata);
ISC_LIST_UNLINK(sigrdatalist.rdata, rdata, link);
isc_mem_put(mctx, rdata->data, BUFSIZE);
isc_mem_put(mctx, rdata, sizeof *rdata);
}
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));
}
if (log != NULL)
isc_log_destroy(&log);
isc_mem_free(mctx, output);
isc_mem_destroy(&mctx);
return (0);
}