00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020
00021 #include <stdlib.h>
00022
00023 #include <isc/buffer.h>
00024 #include <isc/commandline.h>
00025 #include <isc/entropy.h>
00026 #include <isc/hash.h>
00027 #include <isc/mem.h>
00028 #include <isc/print.h>
00029 #include <isc/string.h>
00030 #include <isc/util.h>
00031
00032 #include <dns/callbacks.h>
00033 #include <dns/db.h>
00034 #include <dns/dbiterator.h>
00035 #include <dns/ds.h>
00036 #include <dns/fixedname.h>
00037 #include <dns/keyvalues.h>
00038 #include <dns/log.h>
00039 #include <dns/master.h>
00040 #include <dns/name.h>
00041 #include <dns/rdata.h>
00042 #include <dns/rdataclass.h>
00043 #include <dns/rdataset.h>
00044 #include <dns/rdatasetiter.h>
00045 #include <dns/rdatatype.h>
00046 #include <dns/result.h>
00047
00048 #include <dst/dst.h>
00049
00050 #ifdef PKCS11CRYPTO
00051 #include <pk11/result.h>
00052 #endif
00053
00054 #include "dnssectool.h"
00055
00056 #ifndef PATH_MAX
00057 #define PATH_MAX 1024
00058 #endif
00059
00060 const char *program = "dnssec-importkey";
00061 int verbose;
00062
00063 static dns_rdataclass_t rdclass;
00064 static dns_fixedname_t fixed;
00065 static dns_name_t *name = NULL;
00066 static isc_mem_t *mctx = NULL;
00067 static isc_boolean_t setpub = ISC_FALSE, setdel = ISC_FALSE;
00068 static isc_boolean_t setttl = ISC_FALSE;
00069 static isc_stdtime_t pub = 0, del = 0;
00070 static dns_ttl_t ttl = 0;
00071
00072 static isc_result_t
00073 initname(char *setname) {
00074 isc_result_t result;
00075 isc_buffer_t buf;
00076
00077 dns_fixedname_init(&fixed);
00078 name = dns_fixedname_name(&fixed);
00079
00080 isc_buffer_init(&buf, setname, strlen(setname));
00081 isc_buffer_add(&buf, strlen(setname));
00082 result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
00083 return (result);
00084 }
00085
00086 static void
00087 db_load_from_stream(dns_db_t *db, FILE *fp) {
00088 isc_result_t result;
00089 dns_rdatacallbacks_t callbacks;
00090
00091 dns_rdatacallbacks_init(&callbacks);
00092 result = dns_db_beginload(db, &callbacks);
00093 if (result != ISC_R_SUCCESS)
00094 fatal("dns_db_beginload failed: %s", isc_result_totext(result));
00095
00096 result = dns_master_loadstream(fp, name, name, rdclass, 0,
00097 &callbacks, mctx);
00098 if (result != ISC_R_SUCCESS)
00099 fatal("can't load from input: %s", isc_result_totext(result));
00100
00101 result = dns_db_endload(db, &callbacks);
00102 if (result != ISC_R_SUCCESS)
00103 fatal("dns_db_endload failed: %s", isc_result_totext(result));
00104 }
00105
00106 static isc_result_t
00107 loadset(const char *filename, dns_rdataset_t *rdataset) {
00108 isc_result_t result;
00109 dns_db_t *db = NULL;
00110 dns_dbnode_t *node = NULL;
00111 char setname[DNS_NAME_FORMATSIZE];
00112
00113 dns_name_format(name, setname, sizeof(setname));
00114
00115 result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
00116 rdclass, 0, NULL, &db);
00117 if (result != ISC_R_SUCCESS)
00118 fatal("can't create database");
00119
00120 if (strcmp(filename, "-") == 0) {
00121 db_load_from_stream(db, stdin);
00122 filename = "input";
00123 } else {
00124 result = dns_db_load3(db, filename, dns_masterformat_text,
00125 DNS_MASTER_NOTTL);
00126 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
00127 fatal("can't load %s: %s", filename,
00128 isc_result_totext(result));
00129 }
00130
00131 result = dns_db_findnode(db, name, ISC_FALSE, &node);
00132 if (result != ISC_R_SUCCESS)
00133 fatal("can't find %s node in %s", setname, filename);
00134
00135 result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey,
00136 0, 0, rdataset, NULL);
00137
00138 if (result == ISC_R_NOTFOUND)
00139 fatal("no DNSKEY RR for %s in %s", setname, filename);
00140 else if (result != ISC_R_SUCCESS)
00141 fatal("dns_db_findrdataset");
00142
00143 if (node != NULL)
00144 dns_db_detachnode(db, &node);
00145 if (db != NULL)
00146 dns_db_detach(&db);
00147 return (result);
00148 }
00149
00150 static void
00151 loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
00152 dns_rdata_t *rdata)
00153 {
00154 isc_result_t result;
00155 dst_key_t *key = NULL;
00156 isc_buffer_t keyb;
00157 isc_region_t r;
00158
00159 dns_rdata_init(rdata);
00160
00161 isc_buffer_init(&keyb, key_buf, key_buf_size);
00162
00163 result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
00164 mctx, &key);
00165 if (result != ISC_R_SUCCESS)
00166 fatal("invalid keyfile name %s: %s",
00167 filename, isc_result_totext(result));
00168
00169 if (verbose > 2) {
00170 char keystr[DST_KEY_FORMATSIZE];
00171
00172 dst_key_format(key, keystr, sizeof(keystr));
00173 fprintf(stderr, "%s: %s\n", program, keystr);
00174 }
00175
00176 result = dst_key_todns(key, &keyb);
00177 if (result != ISC_R_SUCCESS)
00178 fatal("can't decode key");
00179
00180 isc_buffer_usedregion(&keyb, &r);
00181 dns_rdata_fromregion(rdata, dst_key_class(key),
00182 dns_rdatatype_dnskey, &r);
00183
00184 rdclass = dst_key_class(key);
00185
00186 dns_fixedname_init(&fixed);
00187 name = dns_fixedname_name(&fixed);
00188 result = dns_name_copy(dst_key_name(key), name, NULL);
00189 if (result != ISC_R_SUCCESS)
00190 fatal("can't copy name");
00191
00192 dst_key_free(&key);
00193 }
00194
00195 static void
00196 emit(const char *dir, dns_rdata_t *rdata) {
00197 isc_result_t result;
00198 char keystr[DST_KEY_FORMATSIZE];
00199 char pubname[1024];
00200 char priname[1024];
00201 isc_buffer_t buf;
00202 dst_key_t *key = NULL, *tmp = NULL;
00203
00204 isc_buffer_init(&buf, rdata->data, rdata->length);
00205 isc_buffer_add(&buf, rdata->length);
00206 result = dst_key_fromdns(name, rdclass, &buf, mctx, &key);
00207 if (result != ISC_R_SUCCESS) {
00208 fatal("dst_key_fromdns: %s", isc_result_totext(result));
00209 }
00210
00211 isc_buffer_init(&buf, pubname, sizeof(pubname));
00212 result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf);
00213 if (result != ISC_R_SUCCESS) {
00214 fatal("Failed to build public key filename: %s",
00215 isc_result_totext(result));
00216 }
00217 isc_buffer_init(&buf, priname, sizeof(priname));
00218 result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
00219 if (result != ISC_R_SUCCESS) {
00220 fatal("Failed to build private key filename: %s",
00221 isc_result_totext(result));
00222 }
00223
00224 result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
00225 dst_key_alg(key),
00226 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
00227 dir, mctx, &tmp);
00228 if (result == ISC_R_SUCCESS) {
00229 if (dst_key_isprivate(tmp) && !dst_key_isexternal(tmp))
00230 fatal("Private key already exists in %s", priname);
00231 dst_key_free(&tmp);
00232 }
00233
00234 dst_key_setexternal(key, ISC_TRUE);
00235 if (setpub)
00236 dst_key_settime(key, DST_TIME_PUBLISH, pub);
00237 if (setdel)
00238 dst_key_settime(key, DST_TIME_DELETE, del);
00239 if (setttl)
00240 dst_key_setttl(key, ttl);
00241
00242 result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
00243 dir);
00244 if (result != ISC_R_SUCCESS) {
00245 dst_key_format(key, keystr, sizeof(keystr));
00246 fatal("Failed to write key %s: %s", keystr,
00247 isc_result_totext(result));
00248 }
00249 printf("%s\n", pubname);
00250
00251 isc_buffer_clear(&buf);
00252 result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
00253 if (result != ISC_R_SUCCESS) {
00254 fatal("Failed to build private key filename: %s",
00255 isc_result_totext(result));
00256 }
00257 printf("%s\n", priname);
00258 dst_key_free(&key);
00259 }
00260
00261 ISC_PLATFORM_NORETURN_PRE static void
00262 usage(void) ISC_PLATFORM_NORETURN_POST;
00263
00264 static void
00265 usage(void) {
00266 fprintf(stderr, "Usage:\n");
00267 fprintf(stderr, " %s options [-K dir] keyfile\n\n", program);
00268 fprintf(stderr, " %s options -f file [keyname]\n\n", program);
00269 fprintf(stderr, "Version: %s\n", VERSION);
00270 fprintf(stderr, "Options:\n");
00271 fprintf(stderr, " -f file: read key from zone file\n");
00272 fprintf(stderr, " -K <directory>: directory in which to store "
00273 "the key files\n");
00274 fprintf(stderr, " -L ttl: set default key TTL\n");
00275 fprintf(stderr, " -v <verbose level>\n");
00276 fprintf(stderr, " -V: print version information\n");
00277 fprintf(stderr, " -h: print usage and exit\n");
00278 fprintf(stderr, "Timing options:\n");
00279 fprintf(stderr, " -P date/[+-]offset/none: set/unset key "
00280 "publication date\n");
00281 fprintf(stderr, " -D date/[+-]offset/none: set/unset key "
00282 "deletion date\n");
00283
00284 exit (-1);
00285 }
00286
00287 int
00288 main(int argc, char **argv) {
00289 char *classname = NULL;
00290 char *filename = NULL, *dir = NULL, *namestr;
00291 char *endp;
00292 int ch;
00293 isc_result_t result;
00294 isc_log_t *log = NULL;
00295 isc_entropy_t *ectx = NULL;
00296 dns_rdataset_t rdataset;
00297 dns_rdata_t rdata;
00298 isc_stdtime_t now;
00299
00300 dns_rdata_init(&rdata);
00301 isc_stdtime_get(&now);
00302
00303 if (argc == 1)
00304 usage();
00305
00306 result = isc_mem_create(0, 0, &mctx);
00307 if (result != ISC_R_SUCCESS)
00308 fatal("out of memory");
00309
00310 #ifdef PKCS11CRYPTO
00311 pk11_result_register();
00312 #endif
00313 dns_result_register();
00314
00315 isc_commandline_errprint = ISC_FALSE;
00316
00317 #define CMDLINE_FLAGS "D:f:hK:L:P:v:V"
00318 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
00319 switch (ch) {
00320 case 'D':
00321 if (setdel)
00322 fatal("-D specified more than once");
00323
00324 del = strtotime(isc_commandline_argument,
00325 now, now, &setdel);
00326 break;
00327 case 'K':
00328 dir = isc_commandline_argument;
00329 if (strlen(dir) == 0U)
00330 fatal("directory must be non-empty string");
00331 break;
00332 case 'L':
00333 ttl = strtottl(isc_commandline_argument);
00334 setttl = ISC_TRUE;
00335 break;
00336 case 'P':
00337 if (setpub)
00338 fatal("-P specified more than once");
00339
00340 pub = strtotime(isc_commandline_argument,
00341 now, now, &setpub);
00342 break;
00343 case 'f':
00344 filename = isc_commandline_argument;
00345 break;
00346 case 'v':
00347 verbose = strtol(isc_commandline_argument, &endp, 0);
00348 if (*endp != '\0')
00349 fatal("-v must be followed by a number");
00350 break;
00351 case '?':
00352 if (isc_commandline_option != '?')
00353 fprintf(stderr, "%s: invalid argument -%c\n",
00354 program, isc_commandline_option);
00355
00356 case 'h':
00357
00358 usage();
00359
00360 case 'V':
00361
00362 version(program);
00363
00364 default:
00365 fprintf(stderr, "%s: unhandled option -%c\n",
00366 program, isc_commandline_option);
00367 exit(1);
00368 }
00369 }
00370
00371 rdclass = strtoclass(classname);
00372
00373 if (argc < isc_commandline_index + 1 && filename == NULL)
00374 fatal("the key file name was not specified");
00375 if (argc > isc_commandline_index + 1)
00376 fatal("extraneous arguments");
00377
00378 if (ectx == NULL)
00379 setup_entropy(mctx, NULL, &ectx);
00380 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
00381 if (result != ISC_R_SUCCESS)
00382 fatal("could not initialize hash");
00383 result = dst_lib_init(mctx, ectx,
00384 ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
00385 if (result != ISC_R_SUCCESS)
00386 fatal("could not initialize dst: %s",
00387 isc_result_totext(result));
00388 isc_entropy_stopcallbacksources(ectx);
00389
00390 setup_logging(mctx, &log);
00391
00392 dns_rdataset_init(&rdataset);
00393
00394 if (filename != NULL) {
00395 if (argc < isc_commandline_index + 1) {
00396
00397 namestr = filename;
00398 } else
00399 namestr = argv[isc_commandline_index];
00400
00401 result = initname(namestr);
00402 if (result != ISC_R_SUCCESS)
00403 fatal("could not initialize name %s", namestr);
00404
00405 result = loadset(filename, &rdataset);
00406
00407 if (result != ISC_R_SUCCESS)
00408 fatal("could not load DNSKEY set: %s\n",
00409 isc_result_totext(result));
00410
00411 for (result = dns_rdataset_first(&rdataset);
00412 result == ISC_R_SUCCESS;
00413 result = dns_rdataset_next(&rdataset)) {
00414
00415 dns_rdata_init(&rdata);
00416 dns_rdataset_current(&rdataset, &rdata);
00417 emit(dir, &rdata);
00418 }
00419 } else {
00420 unsigned char key_buf[DST_KEY_MAXSIZE];
00421
00422 loadkey(argv[isc_commandline_index], key_buf,
00423 DST_KEY_MAXSIZE, &rdata);
00424
00425 emit(dir, &rdata);
00426 }
00427
00428 if (dns_rdataset_isassociated(&rdataset))
00429 dns_rdataset_disassociate(&rdataset);
00430 cleanup_logging(&log);
00431 dst_lib_destroy();
00432 isc_hash_destroy();
00433 cleanup_entropy(&ectx);
00434 dns_name_destroy();
00435 if (verbose > 10)
00436 isc_mem_stats(mctx, stdout);
00437 isc_mem_destroy(&mctx);
00438
00439 fflush(stdout);
00440 if (ferror(stdout)) {
00441 fprintf(stderr, "write error\n");
00442 return (1);
00443 } else
00444 return (0);
00445 }