1*00b67f09SDavid van Moolenbroek /* $NetBSD: keygen.c,v 1.6 2014/12/10 04:37:51 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2009, 2012-2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek *
6*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek *
10*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek */
18*00b67f09SDavid van Moolenbroek
19*00b67f09SDavid van Moolenbroek /* Id: keygen.c,v 1.4 2009/11/12 14:02:38 marka Exp */
20*00b67f09SDavid van Moolenbroek
21*00b67f09SDavid van Moolenbroek /*! \file */
22*00b67f09SDavid van Moolenbroek
23*00b67f09SDavid van Moolenbroek #include <config.h>
24*00b67f09SDavid van Moolenbroek
25*00b67f09SDavid van Moolenbroek #include <stdlib.h>
26*00b67f09SDavid van Moolenbroek #include <stdarg.h>
27*00b67f09SDavid van Moolenbroek
28*00b67f09SDavid van Moolenbroek #include <isc/base64.h>
29*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
30*00b67f09SDavid van Moolenbroek #include <isc/entropy.h>
31*00b67f09SDavid van Moolenbroek #include <isc/file.h>
32*00b67f09SDavid van Moolenbroek #include <isc/keyboard.h>
33*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
34*00b67f09SDavid van Moolenbroek #include <isc/result.h>
35*00b67f09SDavid van Moolenbroek #include <isc/string.h>
36*00b67f09SDavid van Moolenbroek
37*00b67f09SDavid van Moolenbroek #include <dns/keyvalues.h>
38*00b67f09SDavid van Moolenbroek #include <dns/name.h>
39*00b67f09SDavid van Moolenbroek
40*00b67f09SDavid van Moolenbroek #include <dst/dst.h>
41*00b67f09SDavid van Moolenbroek #include <confgen/os.h>
42*00b67f09SDavid van Moolenbroek
43*00b67f09SDavid van Moolenbroek #include "util.h"
44*00b67f09SDavid van Moolenbroek #include "keygen.h"
45*00b67f09SDavid van Moolenbroek
46*00b67f09SDavid van Moolenbroek /*%
47*00b67f09SDavid van Moolenbroek * Convert algorithm type to string.
48*00b67f09SDavid van Moolenbroek */
49*00b67f09SDavid van Moolenbroek const char *
alg_totext(dns_secalg_t alg)50*00b67f09SDavid van Moolenbroek alg_totext(dns_secalg_t alg) {
51*00b67f09SDavid van Moolenbroek switch (alg) {
52*00b67f09SDavid van Moolenbroek case DST_ALG_HMACMD5:
53*00b67f09SDavid van Moolenbroek return "hmac-md5";
54*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA1:
55*00b67f09SDavid van Moolenbroek return "hmac-sha1";
56*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA224:
57*00b67f09SDavid van Moolenbroek return "hmac-sha224";
58*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA256:
59*00b67f09SDavid van Moolenbroek return "hmac-sha256";
60*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA384:
61*00b67f09SDavid van Moolenbroek return "hmac-sha384";
62*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA512:
63*00b67f09SDavid van Moolenbroek return "hmac-sha512";
64*00b67f09SDavid van Moolenbroek default:
65*00b67f09SDavid van Moolenbroek return "(unknown)";
66*00b67f09SDavid van Moolenbroek }
67*00b67f09SDavid van Moolenbroek }
68*00b67f09SDavid van Moolenbroek
69*00b67f09SDavid van Moolenbroek /*%
70*00b67f09SDavid van Moolenbroek * Convert string to algorithm type.
71*00b67f09SDavid van Moolenbroek */
72*00b67f09SDavid van Moolenbroek dns_secalg_t
alg_fromtext(const char * name)73*00b67f09SDavid van Moolenbroek alg_fromtext(const char *name) {
74*00b67f09SDavid van Moolenbroek const char *p = name;
75*00b67f09SDavid van Moolenbroek if (strncasecmp(p, "hmac-", 5) == 0)
76*00b67f09SDavid van Moolenbroek p = &name[5];
77*00b67f09SDavid van Moolenbroek
78*00b67f09SDavid van Moolenbroek if (strcasecmp(p, "md5") == 0)
79*00b67f09SDavid van Moolenbroek return DST_ALG_HMACMD5;
80*00b67f09SDavid van Moolenbroek if (strcasecmp(p, "sha1") == 0)
81*00b67f09SDavid van Moolenbroek return DST_ALG_HMACSHA1;
82*00b67f09SDavid van Moolenbroek if (strcasecmp(p, "sha224") == 0)
83*00b67f09SDavid van Moolenbroek return DST_ALG_HMACSHA224;
84*00b67f09SDavid van Moolenbroek if (strcasecmp(p, "sha256") == 0)
85*00b67f09SDavid van Moolenbroek return DST_ALG_HMACSHA256;
86*00b67f09SDavid van Moolenbroek if (strcasecmp(p, "sha384") == 0)
87*00b67f09SDavid van Moolenbroek return DST_ALG_HMACSHA384;
88*00b67f09SDavid van Moolenbroek if (strcasecmp(p, "sha512") == 0)
89*00b67f09SDavid van Moolenbroek return DST_ALG_HMACSHA512;
90*00b67f09SDavid van Moolenbroek return DST_ALG_UNKNOWN;
91*00b67f09SDavid van Moolenbroek }
92*00b67f09SDavid van Moolenbroek
93*00b67f09SDavid van Moolenbroek /*%
94*00b67f09SDavid van Moolenbroek * Return default keysize for a given algorithm type.
95*00b67f09SDavid van Moolenbroek */
96*00b67f09SDavid van Moolenbroek int
alg_bits(dns_secalg_t alg)97*00b67f09SDavid van Moolenbroek alg_bits(dns_secalg_t alg) {
98*00b67f09SDavid van Moolenbroek switch (alg) {
99*00b67f09SDavid van Moolenbroek case DST_ALG_HMACMD5:
100*00b67f09SDavid van Moolenbroek return 128;
101*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA1:
102*00b67f09SDavid van Moolenbroek return 160;
103*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA224:
104*00b67f09SDavid van Moolenbroek return 224;
105*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA256:
106*00b67f09SDavid van Moolenbroek return 256;
107*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA384:
108*00b67f09SDavid van Moolenbroek return 384;
109*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA512:
110*00b67f09SDavid van Moolenbroek return 512;
111*00b67f09SDavid van Moolenbroek default:
112*00b67f09SDavid van Moolenbroek return 0;
113*00b67f09SDavid van Moolenbroek }
114*00b67f09SDavid van Moolenbroek }
115*00b67f09SDavid van Moolenbroek
116*00b67f09SDavid van Moolenbroek /*%
117*00b67f09SDavid van Moolenbroek * Generate a key of size 'keysize' using entropy source 'randomfile',
118*00b67f09SDavid van Moolenbroek * and place it in 'key_txtbuffer'
119*00b67f09SDavid van Moolenbroek */
120*00b67f09SDavid van Moolenbroek void
generate_key(isc_mem_t * mctx,const char * randomfile,dns_secalg_t alg,int keysize,isc_buffer_t * key_txtbuffer)121*00b67f09SDavid van Moolenbroek generate_key(isc_mem_t *mctx, const char *randomfile, dns_secalg_t alg,
122*00b67f09SDavid van Moolenbroek int keysize, isc_buffer_t *key_txtbuffer) {
123*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
124*00b67f09SDavid van Moolenbroek isc_entropysource_t *entropy_source = NULL;
125*00b67f09SDavid van Moolenbroek int open_keyboard = ISC_ENTROPY_KEYBOARDMAYBE;
126*00b67f09SDavid van Moolenbroek int entropy_flags = 0;
127*00b67f09SDavid van Moolenbroek isc_entropy_t *ectx = NULL;
128*00b67f09SDavid van Moolenbroek isc_buffer_t key_rawbuffer;
129*00b67f09SDavid van Moolenbroek isc_region_t key_rawregion;
130*00b67f09SDavid van Moolenbroek char key_rawsecret[64];
131*00b67f09SDavid van Moolenbroek dst_key_t *key = NULL;
132*00b67f09SDavid van Moolenbroek
133*00b67f09SDavid van Moolenbroek switch (alg) {
134*00b67f09SDavid van Moolenbroek case DST_ALG_HMACMD5:
135*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA1:
136*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA224:
137*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA256:
138*00b67f09SDavid van Moolenbroek if (keysize < 1 || keysize > 512)
139*00b67f09SDavid van Moolenbroek fatal("keysize %d out of range (must be 1-512)\n",
140*00b67f09SDavid van Moolenbroek keysize);
141*00b67f09SDavid van Moolenbroek break;
142*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA384:
143*00b67f09SDavid van Moolenbroek case DST_ALG_HMACSHA512:
144*00b67f09SDavid van Moolenbroek if (keysize < 1 || keysize > 1024)
145*00b67f09SDavid van Moolenbroek fatal("keysize %d out of range (must be 1-1024)\n",
146*00b67f09SDavid van Moolenbroek keysize);
147*00b67f09SDavid van Moolenbroek break;
148*00b67f09SDavid van Moolenbroek default:
149*00b67f09SDavid van Moolenbroek fatal("unsupported algorithm %d\n", alg);
150*00b67f09SDavid van Moolenbroek }
151*00b67f09SDavid van Moolenbroek
152*00b67f09SDavid van Moolenbroek
153*00b67f09SDavid van Moolenbroek DO("create entropy context", isc_entropy_create(mctx, &ectx));
154*00b67f09SDavid van Moolenbroek
155*00b67f09SDavid van Moolenbroek if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
156*00b67f09SDavid van Moolenbroek randomfile = NULL;
157*00b67f09SDavid van Moolenbroek open_keyboard = ISC_ENTROPY_KEYBOARDYES;
158*00b67f09SDavid van Moolenbroek }
159*00b67f09SDavid van Moolenbroek DO("start entropy source", isc_entropy_usebestsource(ectx,
160*00b67f09SDavid van Moolenbroek &entropy_source,
161*00b67f09SDavid van Moolenbroek randomfile,
162*00b67f09SDavid van Moolenbroek open_keyboard));
163*00b67f09SDavid van Moolenbroek
164*00b67f09SDavid van Moolenbroek entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY;
165*00b67f09SDavid van Moolenbroek
166*00b67f09SDavid van Moolenbroek DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags));
167*00b67f09SDavid van Moolenbroek
168*00b67f09SDavid van Moolenbroek DO("generate key", dst_key_generate(dns_rootname, alg,
169*00b67f09SDavid van Moolenbroek keysize, 0, 0,
170*00b67f09SDavid van Moolenbroek DNS_KEYPROTO_ANY,
171*00b67f09SDavid van Moolenbroek dns_rdataclass_in, mctx, &key));
172*00b67f09SDavid van Moolenbroek
173*00b67f09SDavid van Moolenbroek isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
174*00b67f09SDavid van Moolenbroek
175*00b67f09SDavid van Moolenbroek DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer));
176*00b67f09SDavid van Moolenbroek
177*00b67f09SDavid van Moolenbroek isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
178*00b67f09SDavid van Moolenbroek
179*00b67f09SDavid van Moolenbroek DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "",
180*00b67f09SDavid van Moolenbroek key_txtbuffer));
181*00b67f09SDavid van Moolenbroek
182*00b67f09SDavid van Moolenbroek /*
183*00b67f09SDavid van Moolenbroek * Shut down the entropy source now so the "stop typing" message
184*00b67f09SDavid van Moolenbroek * does not muck with the output.
185*00b67f09SDavid van Moolenbroek */
186*00b67f09SDavid van Moolenbroek if (entropy_source != NULL)
187*00b67f09SDavid van Moolenbroek isc_entropy_destroysource(&entropy_source);
188*00b67f09SDavid van Moolenbroek
189*00b67f09SDavid van Moolenbroek if (key != NULL)
190*00b67f09SDavid van Moolenbroek dst_key_free(&key);
191*00b67f09SDavid van Moolenbroek
192*00b67f09SDavid van Moolenbroek isc_entropy_detach(&ectx);
193*00b67f09SDavid van Moolenbroek dst_lib_destroy();
194*00b67f09SDavid van Moolenbroek }
195*00b67f09SDavid van Moolenbroek
196*00b67f09SDavid van Moolenbroek /*%
197*00b67f09SDavid van Moolenbroek * Write a key file to 'keyfile'. If 'user' is non-NULL,
198*00b67f09SDavid van Moolenbroek * make that user the owner of the file. The key will have
199*00b67f09SDavid van Moolenbroek * the name 'keyname' and the secret in the buffer 'secret'.
200*00b67f09SDavid van Moolenbroek */
201*00b67f09SDavid van Moolenbroek void
write_key_file(const char * keyfile,const char * user,const char * keyname,isc_buffer_t * secret,dns_secalg_t alg)202*00b67f09SDavid van Moolenbroek write_key_file(const char *keyfile, const char *user,
203*00b67f09SDavid van Moolenbroek const char *keyname, isc_buffer_t *secret,
204*00b67f09SDavid van Moolenbroek dns_secalg_t alg) {
205*00b67f09SDavid van Moolenbroek isc_result_t result;
206*00b67f09SDavid van Moolenbroek const char *algname = alg_totext(alg);
207*00b67f09SDavid van Moolenbroek FILE *fd = NULL;
208*00b67f09SDavid van Moolenbroek
209*00b67f09SDavid van Moolenbroek DO("create keyfile", isc_file_safecreate(keyfile, &fd));
210*00b67f09SDavid van Moolenbroek
211*00b67f09SDavid van Moolenbroek if (user != NULL) {
212*00b67f09SDavid van Moolenbroek if (set_user(fd, user) == -1)
213*00b67f09SDavid van Moolenbroek fatal("unable to set file owner\n");
214*00b67f09SDavid van Moolenbroek }
215*00b67f09SDavid van Moolenbroek
216*00b67f09SDavid van Moolenbroek fprintf(fd, "key \"%s\" {\n\talgorithm %s;\n"
217*00b67f09SDavid van Moolenbroek "\tsecret \"%.*s\";\n};\n",
218*00b67f09SDavid van Moolenbroek keyname, algname,
219*00b67f09SDavid van Moolenbroek (int)isc_buffer_usedlength(secret),
220*00b67f09SDavid van Moolenbroek (char *)isc_buffer_base(secret));
221*00b67f09SDavid van Moolenbroek fflush(fd);
222*00b67f09SDavid van Moolenbroek if (ferror(fd))
223*00b67f09SDavid van Moolenbroek fatal("write to %s failed\n", keyfile);
224*00b67f09SDavid van Moolenbroek if (fclose(fd))
225*00b67f09SDavid van Moolenbroek fatal("fclose(%s) failed\n", keyfile);
226*00b67f09SDavid van Moolenbroek fprintf(stderr, "wrote key file \"%s\"\n", keyfile);
227*00b67f09SDavid van Moolenbroek }
228*00b67f09SDavid van Moolenbroek
229