dnssec-importkey.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013-2015  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /*! \file */
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   /* AIX, WIN32, and others don't define this. */
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                         /* FALLTHROUGH */
00356                 case 'h':
00357                         /* Does not return. */
00358                         usage();
00359 
00360                 case 'V':
00361                         /* Does not return. */
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                         /* using filename as zone name */
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 }

Generated on Tue Apr 28 17:40:53 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha