]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/bin/dnssec/dnssec-keyfromlabel.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / bin / dnssec / dnssec-keyfromlabel.c
1 /*
2  * Copyright (C) 2007, 2008, 2010  Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 /* $Id: dnssec-keyfromlabel.c,v 1.4.50.2 2010/01/15 23:47:31 tbox Exp $ */
18
19 /*! \file */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24
25 #include <isc/buffer.h>
26 #include <isc/commandline.h>
27 #include <isc/entropy.h>
28 #include <isc/mem.h>
29 #include <isc/region.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
32
33 #include <dns/fixedname.h>
34 #include <dns/keyvalues.h>
35 #include <dns/log.h>
36 #include <dns/name.h>
37 #include <dns/rdataclass.h>
38 #include <dns/result.h>
39 #include <dns/secalg.h>
40
41 #include <dst/dst.h>
42
43 #include "dnssectool.h"
44
45 #define MAX_RSA 4096 /* should be long enough... */
46
47 const char *program = "dnssec-keyfromlabel";
48 int verbose;
49
50 static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 |"
51                           " NSEC3DSA | NSEC3RSASHA1 |"
52                           " RSASHA256 | RSASHA512";
53
54 static void
55 usage(void) {
56         fprintf(stderr, "Usage:\n");
57         fprintf(stderr, "    %s -a alg -l label [options] name\n\n",
58                 program);
59         fprintf(stderr, "Version: %s\n", VERSION);
60         fprintf(stderr, "Required options:\n");
61         fprintf(stderr, "    -a algorithm: %s\n", algs);
62         fprintf(stderr, "    -l label: label of the key\n");
63         fprintf(stderr, "    name: owner of the key\n");
64         fprintf(stderr, "Other options:\n");
65         fprintf(stderr, "    -n nametype: ZONE | HOST | ENTITY | USER | OTHER\n");
66         fprintf(stderr, "        (DNSKEY generation defaults to ZONE\n");
67         fprintf(stderr, "    -c <class> (default: IN)\n");
68         fprintf(stderr, "    -f keyflag: KSK\n");
69         fprintf(stderr, "    -t <type>: "
70                 "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
71                 "(default: AUTHCONF)\n");
72         fprintf(stderr, "    -p <protocol>: "
73                "default: 3 [dnssec]\n");
74         fprintf(stderr, "    -v <verbose level>\n");
75         fprintf(stderr, "    -k : generate a TYPE=KEY key\n");
76         fprintf(stderr, "Output:\n");
77         fprintf(stderr, "     K<name>+<alg>+<id>.key, "
78                 "K<name>+<alg>+<id>.private\n");
79
80         exit (-1);
81 }
82
83 int
84 main(int argc, char **argv) {
85         char            *algname = NULL, *nametype = NULL, *type = NULL;
86         char            *classname = NULL;
87         char            *endp;
88         dst_key_t       *key = NULL, *oldkey;
89         dns_fixedname_t fname;
90         dns_name_t      *name;
91         isc_uint16_t    flags = 0, ksk = 0;
92         dns_secalg_t    alg;
93         isc_boolean_t   null_key = ISC_FALSE;
94         isc_mem_t       *mctx = NULL;
95         int             ch;
96         int             protocol = -1, signatory = 0;
97         isc_result_t    ret;
98         isc_textregion_t r;
99         char            filename[255];
100         isc_buffer_t    buf;
101         isc_log_t       *log = NULL;
102         isc_entropy_t   *ectx = NULL;
103         dns_rdataclass_t rdclass;
104         int             options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC;
105         char            *label = NULL;
106
107         if (argc == 1)
108                 usage();
109
110         RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
111
112         dns_result_register();
113
114         isc_commandline_errprint = ISC_FALSE;
115
116         while ((ch = isc_commandline_parse(argc, argv,
117                                          "a:c:f:kl:n:p:t:v:h")) != -1)
118         {
119             switch (ch) {
120                 case 'a':
121                         algname = isc_commandline_argument;
122                         break;
123                 case 'c':
124                         classname = isc_commandline_argument;
125                         break;
126                 case 'f':
127                         if (strcasecmp(isc_commandline_argument, "KSK") == 0)
128                                 ksk = DNS_KEYFLAG_KSK;
129                         else
130                                 fatal("unknown flag '%s'",
131                                       isc_commandline_argument);
132                         break;
133                 case 'k':
134                         options |= DST_TYPE_KEY;
135                         break;
136                 case 'l':
137                         label = isc_commandline_argument;
138                         break;
139                 case 'n':
140                         nametype = isc_commandline_argument;
141                         break;
142                 case 'p':
143                         protocol = strtol(isc_commandline_argument, &endp, 10);
144                         if (*endp != '\0' || protocol < 0 || protocol > 255)
145                                 fatal("-p must be followed by a number "
146                                       "[0..255]");
147                         break;
148                 case 't':
149                         type = isc_commandline_argument;
150                         break;
151                 case 'v':
152                         verbose = strtol(isc_commandline_argument, &endp, 0);
153                         if (*endp != '\0')
154                                 fatal("-v must be followed by a number");
155                         break;
156
157                 case '?':
158                         if (isc_commandline_option != '?')
159                                 fprintf(stderr, "%s: invalid argument -%c\n",
160                                         program, isc_commandline_option);
161                 case 'h':
162                         usage();
163
164                 default:
165                         fprintf(stderr, "%s: unhandled option -%c\n",
166                                 program, isc_commandline_option);
167                         exit(1);
168                 }
169         }
170
171         if (ectx == NULL)
172                 setup_entropy(mctx, NULL, &ectx);
173         ret = dst_lib_init(mctx, ectx,
174                            ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
175         if (ret != ISC_R_SUCCESS)
176                 fatal("could not initialize dst");
177
178         setup_logging(verbose, mctx, &log);
179
180         if (label == NULL)
181                 fatal("the key label was not specified");
182         if (argc < isc_commandline_index + 1)
183                 fatal("the key name was not specified");
184         if (argc > isc_commandline_index + 1)
185                 fatal("extraneous arguments");
186
187         if (algname == NULL)
188                 fatal("no algorithm was specified");
189         if (strcasecmp(algname, "RSA") == 0) {
190                 fprintf(stderr, "The use of RSA (RSAMD5) is not recommended.\n"
191                                 "If you still wish to use RSA (RSAMD5) please "
192                                 "specify \"-a RSAMD5\"\n");
193                 return (1);
194         } else {
195                 r.base = algname;
196                 r.length = strlen(algname);
197                 ret = dns_secalg_fromtext(&alg, &r);
198                 if (ret != ISC_R_SUCCESS)
199                         fatal("unknown algorithm %s", algname);
200                 if (alg == DST_ALG_DH)
201                         options |= DST_TYPE_KEY;
202         }
203
204         if (type != NULL && (options & DST_TYPE_KEY) != 0) {
205                 if (strcasecmp(type, "NOAUTH") == 0)
206                         flags |= DNS_KEYTYPE_NOAUTH;
207                 else if (strcasecmp(type, "NOCONF") == 0)
208                         flags |= DNS_KEYTYPE_NOCONF;
209                 else if (strcasecmp(type, "NOAUTHCONF") == 0) {
210                         flags |= (DNS_KEYTYPE_NOAUTH | DNS_KEYTYPE_NOCONF);
211                 }
212                 else if (strcasecmp(type, "AUTHCONF") == 0)
213                         /* nothing */;
214                 else
215                         fatal("invalid type %s", type);
216         }
217
218         if (nametype == NULL) {
219                 if ((options & DST_TYPE_KEY) != 0) /* KEY */
220                         fatal("no nametype specified");
221                 flags |= DNS_KEYOWNER_ZONE;     /* DNSKEY */
222         } else if (strcasecmp(nametype, "zone") == 0)
223                 flags |= DNS_KEYOWNER_ZONE;
224         else if ((options & DST_TYPE_KEY) != 0) { /* KEY */
225                 if (strcasecmp(nametype, "host") == 0 ||
226                          strcasecmp(nametype, "entity") == 0)
227                         flags |= DNS_KEYOWNER_ENTITY;
228                 else if (strcasecmp(nametype, "user") == 0)
229                         flags |= DNS_KEYOWNER_USER;
230                 else
231                         fatal("invalid KEY nametype %s", nametype);
232         } else if (strcasecmp(nametype, "other") != 0) /* DNSKEY */
233                 fatal("invalid DNSKEY nametype %s", nametype);
234
235         rdclass = strtoclass(classname);
236
237         if ((options & DST_TYPE_KEY) != 0)  /* KEY */
238                 flags |= signatory;
239         else if ((flags & DNS_KEYOWNER_ZONE) != 0) /* DNSKEY */
240                 flags |= ksk;
241
242         if (protocol == -1)
243                 protocol = DNS_KEYPROTO_DNSSEC;
244         else if ((options & DST_TYPE_KEY) == 0 &&
245                  protocol != DNS_KEYPROTO_DNSSEC)
246                 fatal("invalid DNSKEY protocol: %d", protocol);
247
248         if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
249                 if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0)
250                         fatal("specified null key with signing authority");
251         }
252
253         if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE &&
254             alg == DNS_KEYALG_DH)
255                 fatal("a key with algorithm '%s' cannot be a zone key",
256                       algname);
257
258         dns_fixedname_init(&fname);
259         name = dns_fixedname_name(&fname);
260         isc_buffer_init(&buf, argv[isc_commandline_index],
261                         strlen(argv[isc_commandline_index]));
262         isc_buffer_add(&buf, strlen(argv[isc_commandline_index]));
263         ret = dns_name_fromtext(name, &buf, dns_rootname, ISC_FALSE, NULL);
264         if (ret != ISC_R_SUCCESS)
265                 fatal("invalid key name %s: %s", argv[isc_commandline_index],
266                       isc_result_totext(ret));
267
268         if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
269                 null_key = ISC_TRUE;
270
271         isc_buffer_init(&buf, filename, sizeof(filename) - 1);
272
273         /* associate the key */
274         ret = dst_key_fromlabel(name, alg, flags, protocol,
275                                 rdclass, "", label, NULL, mctx, &key);
276         isc_entropy_stopcallbacksources(ectx);
277
278         if (ret != ISC_R_SUCCESS) {
279                 char namestr[DNS_NAME_FORMATSIZE];
280                 char algstr[ALG_FORMATSIZE];
281                 dns_name_format(name, namestr, sizeof(namestr));
282                 alg_format(alg, algstr, sizeof(algstr));
283                 fatal("failed to generate key %s/%s: %s\n",
284                       namestr, algstr, isc_result_totext(ret));
285                 exit(-1);
286         }
287
288         /*
289          * Try to read a key with the same name, alg and id from disk.
290          * If there is one we must continue generating a new one
291          * unless we were asked to generate a null key, in which
292          * case we return failure.
293          */
294         ret = dst_key_fromfile(name, dst_key_id(key), alg,
295                                DST_TYPE_PRIVATE, NULL, mctx, &oldkey);
296         /* do not overwrite an existing key  */
297         if (ret == ISC_R_SUCCESS) {
298                 isc_buffer_clear(&buf);
299                 ret = dst_key_buildfilename(key, 0, NULL, &buf);
300                 fprintf(stderr, "%s: %s already exists\n",
301                         program, filename);
302                 dst_key_free(&key);
303                 exit (1);
304         }
305
306         ret = dst_key_tofile(key, options, NULL);
307         if (ret != ISC_R_SUCCESS) {
308                 char keystr[KEY_FORMATSIZE];
309                 key_format(key, keystr, sizeof(keystr));
310                 fatal("failed to write key %s: %s\n", keystr,
311                       isc_result_totext(ret));
312         }
313
314         isc_buffer_clear(&buf);
315         ret = dst_key_buildfilename(key, 0, NULL, &buf);
316         printf("%s\n", filename);
317         dst_key_free(&key);
318
319         cleanup_logging(&log);
320         cleanup_entropy(&ectx);
321         dst_lib_destroy();
322         dns_name_destroy();
323         if (verbose > 10)
324                 isc_mem_stats(mctx, stdout);
325         isc_mem_destroy(&mctx);
326
327         return (0);
328 }