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