dnssec-dsfromkey.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2012, 2014, 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-dsfromkey";
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_uint32_t     ttl;
00068 static isc_boolean_t    emitttl = ISC_FALSE;
00069 
00070 static isc_result_t
00071 initname(char *setname) {
00072         isc_result_t result;
00073         isc_buffer_t buf;
00074 
00075         dns_fixedname_init(&fixed);
00076         name = dns_fixedname_name(&fixed);
00077 
00078         isc_buffer_init(&buf, setname, strlen(setname));
00079         isc_buffer_add(&buf, strlen(setname));
00080         result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
00081         return (result);
00082 }
00083 
00084 static void
00085 db_load_from_stream(dns_db_t *db, FILE *fp) {
00086         isc_result_t result;
00087         dns_rdatacallbacks_t callbacks;
00088 
00089         dns_rdatacallbacks_init(&callbacks);
00090         result = dns_db_beginload(db, &callbacks);
00091         if (result != ISC_R_SUCCESS)
00092                 fatal("dns_db_beginload failed: %s", isc_result_totext(result));
00093 
00094         result = dns_master_loadstream(fp, name, name, rdclass, 0,
00095                                        &callbacks, mctx);
00096         if (result != ISC_R_SUCCESS)
00097                 fatal("can't load from input: %s", isc_result_totext(result));
00098 
00099         result = dns_db_endload(db, &callbacks);
00100         if (result != ISC_R_SUCCESS)
00101                 fatal("dns_db_endload failed: %s", isc_result_totext(result));
00102 }
00103 
00104 static isc_result_t
00105 loadset(const char *filename, dns_rdataset_t *rdataset) {
00106         isc_result_t     result;
00107         dns_db_t         *db = NULL;
00108         dns_dbnode_t     *node = NULL;
00109         char setname[DNS_NAME_FORMATSIZE];
00110 
00111         dns_name_format(name, setname, sizeof(setname));
00112 
00113         result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
00114                                rdclass, 0, NULL, &db);
00115         if (result != ISC_R_SUCCESS)
00116                 fatal("can't create database");
00117 
00118         if (strcmp(filename, "-") == 0) {
00119                 db_load_from_stream(db, stdin);
00120                 filename = "input";
00121         } else {
00122                 result = dns_db_load(db, filename);
00123                 if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
00124                         fatal("can't load %s: %s", filename,
00125                               isc_result_totext(result));
00126         }
00127 
00128         result = dns_db_findnode(db, name, ISC_FALSE, &node);
00129         if (result != ISC_R_SUCCESS)
00130                 fatal("can't find %s node in %s", setname, filename);
00131 
00132         result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey,
00133                                      0, 0, rdataset, NULL);
00134 
00135         if (result == ISC_R_NOTFOUND)
00136                 fatal("no DNSKEY RR for %s in %s", setname, filename);
00137         else if (result != ISC_R_SUCCESS)
00138                 fatal("dns_db_findrdataset");
00139 
00140         if (node != NULL)
00141                 dns_db_detachnode(db, &node);
00142         if (db != NULL)
00143                 dns_db_detach(&db);
00144         return (result);
00145 }
00146 
00147 static isc_result_t
00148 loadkeyset(char *dirname, dns_rdataset_t *rdataset) {
00149         isc_result_t     result;
00150         char             filename[PATH_MAX + 1];
00151         isc_buffer_t     buf;
00152 
00153         dns_rdataset_init(rdataset);
00154 
00155         isc_buffer_init(&buf, filename, sizeof(filename));
00156         if (dirname != NULL) {
00157                 /* allow room for a trailing slash */
00158                 if (strlen(dirname) >= isc_buffer_availablelength(&buf))
00159                         return (ISC_R_NOSPACE);
00160                 isc_buffer_putstr(&buf, dirname);
00161                 if (dirname[strlen(dirname) - 1] != '/')
00162                         isc_buffer_putstr(&buf, "/");
00163         }
00164 
00165         if (isc_buffer_availablelength(&buf) < 7)
00166                 return (ISC_R_NOSPACE);
00167         isc_buffer_putstr(&buf, "keyset-");
00168 
00169         result = dns_name_tofilenametext(name, ISC_FALSE, &buf);
00170         check_result(result, "dns_name_tofilenametext()");
00171         if (isc_buffer_availablelength(&buf) == 0)
00172                 return (ISC_R_NOSPACE);
00173         isc_buffer_putuint8(&buf, 0);
00174 
00175         return (loadset(filename, rdataset));
00176 }
00177 
00178 static void
00179 loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
00180         dns_rdata_t *rdata)
00181 {
00182         isc_result_t  result;
00183         dst_key_t     *key = NULL;
00184         isc_buffer_t  keyb;
00185         isc_region_t  r;
00186 
00187         dns_rdata_init(rdata);
00188 
00189         isc_buffer_init(&keyb, key_buf, key_buf_size);
00190 
00191         result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
00192                                        mctx, &key);
00193         if (result != ISC_R_SUCCESS)
00194                 fatal("invalid keyfile name %s: %s",
00195                       filename, isc_result_totext(result));
00196 
00197         if (verbose > 2) {
00198                 char keystr[DST_KEY_FORMATSIZE];
00199 
00200                 dst_key_format(key, keystr, sizeof(keystr));
00201                 fprintf(stderr, "%s: %s\n", program, keystr);
00202         }
00203 
00204         result = dst_key_todns(key, &keyb);
00205         if (result != ISC_R_SUCCESS)
00206                 fatal("can't decode key");
00207 
00208         isc_buffer_usedregion(&keyb, &r);
00209         dns_rdata_fromregion(rdata, dst_key_class(key),
00210                              dns_rdatatype_dnskey, &r);
00211 
00212         rdclass = dst_key_class(key);
00213 
00214         dns_fixedname_init(&fixed);
00215         name = dns_fixedname_name(&fixed);
00216         result = dns_name_copy(dst_key_name(key), name, NULL);
00217         if (result != ISC_R_SUCCESS)
00218                 fatal("can't copy name");
00219 
00220         dst_key_free(&key);
00221 }
00222 
00223 static void
00224 logkey(dns_rdata_t *rdata)
00225 {
00226         isc_result_t result;
00227         dst_key_t    *key = NULL;
00228         isc_buffer_t buf;
00229         char         keystr[DST_KEY_FORMATSIZE];
00230 
00231         isc_buffer_init(&buf, rdata->data, rdata->length);
00232         isc_buffer_add(&buf, rdata->length);
00233         result = dst_key_fromdns(name, rdclass, &buf, mctx, &key);
00234         if (result != ISC_R_SUCCESS)
00235                 return;
00236 
00237         dst_key_format(key, keystr, sizeof(keystr));
00238         fprintf(stderr, "%s: %s\n", program, keystr);
00239 
00240         dst_key_free(&key);
00241 }
00242 
00243 static void
00244 emit(unsigned int dtype, isc_boolean_t showall, char *lookaside,
00245      dns_rdata_t *rdata)
00246 {
00247         isc_result_t result;
00248         unsigned char buf[DNS_DS_BUFFERSIZE];
00249         char text_buf[DST_KEY_MAXTEXTSIZE];
00250         char name_buf[DNS_NAME_MAXWIRE];
00251         char class_buf[10];
00252         isc_buffer_t textb, nameb, classb;
00253         isc_region_t r;
00254         dns_rdata_t ds;
00255         dns_rdata_dnskey_t dnskey;
00256 
00257         isc_buffer_init(&textb, text_buf, sizeof(text_buf));
00258         isc_buffer_init(&nameb, name_buf, sizeof(name_buf));
00259         isc_buffer_init(&classb, class_buf, sizeof(class_buf));
00260 
00261         dns_rdata_init(&ds);
00262 
00263         result = dns_rdata_tostruct(rdata, &dnskey, NULL);
00264         if (result != ISC_R_SUCCESS)
00265                 fatal("can't convert DNSKEY");
00266 
00267         if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && !showall)
00268                 return;
00269 
00270         result = dns_ds_buildrdata(name, rdata, dtype, buf, &ds);
00271         if (result != ISC_R_SUCCESS)
00272                 fatal("can't build record");
00273 
00274         result = dns_name_totext(name, ISC_FALSE, &nameb);
00275         if (result != ISC_R_SUCCESS)
00276                 fatal("can't print name");
00277 
00278         /* Add lookaside origin, if set */
00279         if (lookaside != NULL) {
00280                 if (isc_buffer_availablelength(&nameb) < strlen(lookaside))
00281                         fatal("DLV origin '%s' is too long", lookaside);
00282                 isc_buffer_putstr(&nameb, lookaside);
00283                 if (lookaside[strlen(lookaside) - 1] != '.') {
00284                         if (isc_buffer_availablelength(&nameb) < 1)
00285                                 fatal("DLV origin '%s' is too long", lookaside);
00286                         isc_buffer_putstr(&nameb, ".");
00287                 }
00288         }
00289 
00290         result = dns_rdata_tofmttext(&ds, (dns_name_t *) NULL, 0, 0, 0, "",
00291                                      &textb);
00292 
00293         if (result != ISC_R_SUCCESS)
00294                 fatal("can't print rdata");
00295 
00296         result = dns_rdataclass_totext(rdclass, &classb);
00297         if (result != ISC_R_SUCCESS)
00298                 fatal("can't print class");
00299 
00300         isc_buffer_usedregion(&nameb, &r);
00301         printf("%.*s ", (int)r.length, r.base);
00302 
00303         if (emitttl)
00304                 printf("%u ", ttl);
00305 
00306         isc_buffer_usedregion(&classb, &r);
00307         printf("%.*s", (int)r.length, r.base);
00308 
00309         if (lookaside == NULL)
00310                 printf(" DS ");
00311         else
00312                 printf(" DLV ");
00313 
00314         isc_buffer_usedregion(&textb, &r);
00315         printf("%.*s\n", (int)r.length, r.base);
00316 }
00317 
00318 ISC_PLATFORM_NORETURN_PRE static void
00319 usage(void) ISC_PLATFORM_NORETURN_POST;
00320 
00321 static void
00322 usage(void) {
00323         fprintf(stderr, "Usage:\n");
00324         fprintf(stderr, "    %s options [-K dir] keyfile\n\n", program);
00325         fprintf(stderr, "    %s options [-K dir] [-c class] -s dnsname\n\n",
00326                 program);
00327         fprintf(stderr, "    %s options -f zonefile (as zone name)\n\n", program);
00328         fprintf(stderr, "    %s options -f zonefile zonename\n\n", program);
00329         fprintf(stderr, "Version: %s\n", VERSION);
00330         fprintf(stderr, "Options:\n");
00331         fprintf(stderr, "    -v <verbose level>\n");
00332         fprintf(stderr, "    -V: print version information\n");
00333         fprintf(stderr, "    -K <directory>: directory in which to find "
00334                         "key file or keyset file\n");
00335         fprintf(stderr, "    -a algorithm: digest algorithm "
00336                         "(SHA-1, SHA-256, GOST or SHA-384)\n");
00337         fprintf(stderr, "    -1: use SHA-1\n");
00338         fprintf(stderr, "    -2: use SHA-256\n");
00339         fprintf(stderr, "    -l: add lookaside zone and print DLV records\n");
00340         fprintf(stderr, "    -s: read keyset from keyset-<dnsname> file\n");
00341         fprintf(stderr, "    -c class: rdata class for DS set (default: IN)\n");
00342         fprintf(stderr, "    -T TTL\n");
00343         fprintf(stderr, "    -f file: read keyset from zone file\n");
00344         fprintf(stderr, "    -A: when used with -f, "
00345                         "include all keys in DS set, not just KSKs\n");
00346         fprintf(stderr, "Output: DS or DLV RRs\n");
00347 
00348         exit (-1);
00349 }
00350 
00351 int
00352 main(int argc, char **argv) {
00353         char            *algname = NULL, *classname = NULL;
00354         char            *filename = NULL, *dir = NULL, *namestr;
00355         char            *lookaside = NULL;
00356         char            *endp;
00357         int             ch;
00358         unsigned int    dtype = DNS_DSDIGEST_SHA1;
00359         isc_boolean_t   both = ISC_TRUE;
00360         isc_boolean_t   usekeyset = ISC_FALSE;
00361         isc_boolean_t   showall = ISC_FALSE;
00362         isc_result_t    result;
00363         isc_log_t       *log = NULL;
00364         isc_entropy_t   *ectx = NULL;
00365         dns_rdataset_t  rdataset;
00366         dns_rdata_t     rdata;
00367 
00368         dns_rdata_init(&rdata);
00369 
00370         if (argc == 1)
00371                 usage();
00372 
00373         result = isc_mem_create(0, 0, &mctx);
00374         if (result != ISC_R_SUCCESS)
00375                 fatal("out of memory");
00376 
00377 #ifdef PKCS11CRYPTO
00378         pk11_result_register();
00379 #endif
00380         dns_result_register();
00381 
00382         isc_commandline_errprint = ISC_FALSE;
00383 
00384         while ((ch = isc_commandline_parse(argc, argv,
00385                                            "12Aa:c:d:Ff:K:l:sT:v:hV")) != -1) {
00386                 switch (ch) {
00387                 case '1':
00388                         dtype = DNS_DSDIGEST_SHA1;
00389                         both = ISC_FALSE;
00390                         break;
00391                 case '2':
00392                         dtype = DNS_DSDIGEST_SHA256;
00393                         both = ISC_FALSE;
00394                         break;
00395                 case 'A':
00396                         showall = ISC_TRUE;
00397                         break;
00398                 case 'a':
00399                         algname = isc_commandline_argument;
00400                         both = ISC_FALSE;
00401                         break;
00402                 case 'c':
00403                         classname = isc_commandline_argument;
00404                         break;
00405                 case 'd':
00406                         fprintf(stderr, "%s: the -d option is deprecated; "
00407                                         "use -K\n", program);
00408                         /* fall through */
00409                 case 'K':
00410                         dir = isc_commandline_argument;
00411                         if (strlen(dir) == 0U)
00412                                 fatal("directory must be non-empty string");
00413                         break;
00414                 case 'f':
00415                         filename = isc_commandline_argument;
00416                         break;
00417                 case 'l':
00418                         lookaside = isc_commandline_argument;
00419                         if (strlen(lookaside) == 0U)
00420                                 fatal("lookaside must be a non-empty string");
00421                         break;
00422                 case 's':
00423                         usekeyset = ISC_TRUE;
00424                         break;
00425                 case 'T':
00426                         emitttl = ISC_TRUE;
00427                         ttl = atol(isc_commandline_argument);
00428                         break;
00429                 case 'v':
00430                         verbose = strtol(isc_commandline_argument, &endp, 0);
00431                         if (*endp != '\0')
00432                                 fatal("-v must be followed by a number");
00433                         break;
00434                 case 'F':
00435                         /* Reserved for FIPS mode */
00436                         /* FALLTHROUGH */
00437                 case '?':
00438                         if (isc_commandline_option != '?')
00439                                 fprintf(stderr, "%s: invalid argument -%c\n",
00440                                         program, isc_commandline_option);
00441                         /* FALLTHROUGH */
00442                 case 'h':
00443                         /* Does not return. */
00444                         usage();
00445 
00446                 case 'V':
00447                         /* Does not return. */
00448                         version(program);
00449 
00450                 default:
00451                         fprintf(stderr, "%s: unhandled option -%c\n",
00452                                 program, isc_commandline_option);
00453                         exit(1);
00454                 }
00455         }
00456 
00457         if (algname != NULL) {
00458                 if (strcasecmp(algname, "SHA1") == 0 ||
00459                     strcasecmp(algname, "SHA-1") == 0)
00460                         dtype = DNS_DSDIGEST_SHA1;
00461                 else if (strcasecmp(algname, "SHA256") == 0 ||
00462                          strcasecmp(algname, "SHA-256") == 0)
00463                         dtype = DNS_DSDIGEST_SHA256;
00464 #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
00465                 else if (strcasecmp(algname, "GOST") == 0)
00466                         dtype = DNS_DSDIGEST_GOST;
00467 #endif
00468                 else if (strcasecmp(algname, "SHA384") == 0 ||
00469                          strcasecmp(algname, "SHA-384") == 0)
00470                         dtype = DNS_DSDIGEST_SHA384;
00471                 else
00472                         fatal("unknown algorithm %s", algname);
00473         }
00474 
00475         rdclass = strtoclass(classname);
00476 
00477         if (usekeyset && filename != NULL)
00478                 fatal("cannot use both -s and -f");
00479 
00480         /* When not using -f, -A is implicit */
00481         if (filename == NULL)
00482                 showall = ISC_TRUE;
00483 
00484         if (argc < isc_commandline_index + 1 && filename == NULL)
00485                 fatal("the key file name was not specified");
00486         if (argc > isc_commandline_index + 1)
00487                 fatal("extraneous arguments");
00488 
00489         if (ectx == NULL)
00490                 setup_entropy(mctx, NULL, &ectx);
00491         result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
00492         if (result != ISC_R_SUCCESS)
00493                 fatal("could not initialize hash");
00494         result = dst_lib_init(mctx, ectx,
00495                               ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
00496         if (result != ISC_R_SUCCESS)
00497                 fatal("could not initialize dst: %s",
00498                       isc_result_totext(result));
00499         isc_entropy_stopcallbacksources(ectx);
00500 
00501         setup_logging(mctx, &log);
00502 
00503         dns_rdataset_init(&rdataset);
00504 
00505         if (usekeyset || filename != NULL) {
00506                 if (argc < isc_commandline_index + 1 && filename != NULL) {
00507                         /* using zone name as the zone file name */
00508                         namestr = filename;
00509                 } else
00510                         namestr = argv[isc_commandline_index];
00511 
00512                 result = initname(namestr);
00513                 if (result != ISC_R_SUCCESS)
00514                         fatal("could not initialize name %s", namestr);
00515 
00516                 if (usekeyset)
00517                         result = loadkeyset(dir, &rdataset);
00518                 else
00519                         result = loadset(filename, &rdataset);
00520 
00521                 if (result != ISC_R_SUCCESS)
00522                         fatal("could not load DNSKEY set: %s\n",
00523                               isc_result_totext(result));
00524 
00525                 for (result = dns_rdataset_first(&rdataset);
00526                      result == ISC_R_SUCCESS;
00527                      result = dns_rdataset_next(&rdataset)) {
00528                         dns_rdata_init(&rdata);
00529                         dns_rdataset_current(&rdataset, &rdata);
00530 
00531                         if (verbose > 2)
00532                                 logkey(&rdata);
00533 
00534                         if (both) {
00535                                 emit(DNS_DSDIGEST_SHA1, showall, lookaside,
00536                                      &rdata);
00537                                 emit(DNS_DSDIGEST_SHA256, showall, lookaside,
00538                                      &rdata);
00539                         } else
00540                                 emit(dtype, showall, lookaside, &rdata);
00541                 }
00542         } else {
00543                 unsigned char key_buf[DST_KEY_MAXSIZE];
00544 
00545                 loadkey(argv[isc_commandline_index], key_buf,
00546                         DST_KEY_MAXSIZE, &rdata);
00547 
00548                 if (both) {
00549                         emit(DNS_DSDIGEST_SHA1, showall, lookaside, &rdata);
00550                         emit(DNS_DSDIGEST_SHA256, showall, lookaside, &rdata);
00551                 } else
00552                         emit(dtype, showall, lookaside, &rdata);
00553         }
00554 
00555         if (dns_rdataset_isassociated(&rdataset))
00556                 dns_rdataset_disassociate(&rdataset);
00557         cleanup_logging(&log);
00558         dst_lib_destroy();
00559         isc_hash_destroy();
00560         cleanup_entropy(&ectx);
00561         dns_name_destroy();
00562         if (verbose > 10)
00563                 isc_mem_stats(mctx, stdout);
00564         isc_mem_destroy(&mctx);
00565 
00566         fflush(stdout);
00567         if (ferror(stdout)) {
00568                 fprintf(stderr, "write error\n");
00569                 return (1);
00570         } else
00571                 return (0);
00572 }

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