1 /*
2 * Copyright (C) 2009, 2012, 2013, 2015 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: keygen.c,v 1.4 2009/11/12 14:02:38 marka Exp $ */
18
19 /*! \file */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25
26 #include <isc/base64.h>
27 #include <isc/buffer.h>
28 #include <isc/entropy.h>
29 #include <isc/file.h>
30 #include <isc/keyboard.h>
31 #include <isc/mem.h>
32 #include <isc/print.h>
33 #include <isc/result.h>
34 #include <isc/string.h>
35
36 #include <dns/keyvalues.h>
37 #include <dns/name.h>
38
39 #include <dst/dst.h>
40 #include <confgen/os.h>
41
42 #include "util.h"
43 #include "keygen.h"
44
45 /*%
46 * Convert algorithm type to string.
47 */
48 const char *
alg_totext(dns_secalg_t alg)49 alg_totext(dns_secalg_t alg) {
50 switch (alg) {
51 case DST_ALG_HMACMD5:
52 return "hmac-md5";
53 case DST_ALG_HMACSHA1:
54 return "hmac-sha1";
55 case DST_ALG_HMACSHA224:
56 return "hmac-sha224";
57 case DST_ALG_HMACSHA256:
58 return "hmac-sha256";
59 case DST_ALG_HMACSHA384:
60 return "hmac-sha384";
61 case DST_ALG_HMACSHA512:
62 return "hmac-sha512";
63 default:
64 return "(unknown)";
65 }
66 }
67
68 /*%
69 * Convert string to algorithm type.
70 */
71 dns_secalg_t
alg_fromtext(const char * name)72 alg_fromtext(const char *name) {
73 if (strcmp(name, "hmac-md5") == 0)
74 return DST_ALG_HMACMD5;
75 if (strcmp(name, "hmac-sha1") == 0)
76 return DST_ALG_HMACSHA1;
77 if (strcmp(name, "hmac-sha224") == 0)
78 return DST_ALG_HMACSHA224;
79 if (strcmp(name, "hmac-sha256") == 0)
80 return DST_ALG_HMACSHA256;
81 if (strcmp(name, "hmac-sha384") == 0)
82 return DST_ALG_HMACSHA384;
83 if (strcmp(name, "hmac-sha512") == 0)
84 return DST_ALG_HMACSHA512;
85 return DST_ALG_UNKNOWN;
86 }
87
88 /*%
89 * Return default keysize for a given algorithm type.
90 */
91 int
alg_bits(dns_secalg_t alg)92 alg_bits(dns_secalg_t alg) {
93 switch (alg) {
94 case DST_ALG_HMACMD5:
95 return 128;
96 case DST_ALG_HMACSHA1:
97 return 160;
98 case DST_ALG_HMACSHA224:
99 return 224;
100 case DST_ALG_HMACSHA256:
101 return 256;
102 case DST_ALG_HMACSHA384:
103 return 384;
104 case DST_ALG_HMACSHA512:
105 return 512;
106 default:
107 return 0;
108 }
109 }
110
111 /*%
112 * Generate a key of size 'keysize' using entropy source 'randomfile',
113 * and place it in 'key_txtbuffer'
114 */
115 void
generate_key(isc_mem_t * mctx,const char * randomfile,dns_secalg_t alg,int keysize,isc_buffer_t * key_txtbuffer)116 generate_key(isc_mem_t *mctx, const char *randomfile, dns_secalg_t alg,
117 int keysize, isc_buffer_t *key_txtbuffer) {
118 isc_result_t result = ISC_R_SUCCESS;
119 isc_entropysource_t *entropy_source = NULL;
120 int open_keyboard = ISC_ENTROPY_KEYBOARDMAYBE;
121 int entropy_flags = 0;
122 isc_entropy_t *ectx = NULL;
123 isc_buffer_t key_rawbuffer;
124 isc_region_t key_rawregion;
125 char key_rawsecret[64];
126 dst_key_t *key = NULL;
127
128 switch (alg) {
129 case DST_ALG_HMACMD5:
130 case DST_ALG_HMACSHA1:
131 case DST_ALG_HMACSHA224:
132 case DST_ALG_HMACSHA256:
133 if (keysize < 1 || keysize > 512)
134 fatal("keysize %d out of range (must be 1-512)\n",
135 keysize);
136 break;
137 case DST_ALG_HMACSHA384:
138 case DST_ALG_HMACSHA512:
139 if (keysize < 1 || keysize > 1024)
140 fatal("keysize %d out of range (must be 1-1024)\n",
141 keysize);
142 break;
143 default:
144 fatal("unsupported algorithm %d\n", alg);
145 }
146
147
148 DO("create entropy context", isc_entropy_create(mctx, &ectx));
149
150 if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
151 randomfile = NULL;
152 open_keyboard = ISC_ENTROPY_KEYBOARDYES;
153 }
154 DO("start entropy source", isc_entropy_usebestsource(ectx,
155 &entropy_source,
156 randomfile,
157 open_keyboard));
158
159 entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY;
160
161 DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags));
162
163 DO("generate key", dst_key_generate(dns_rootname, alg,
164 keysize, 0, 0,
165 DNS_KEYPROTO_ANY,
166 dns_rdataclass_in, mctx, &key));
167
168 isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
169
170 DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer));
171
172 isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
173
174 DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "",
175 key_txtbuffer));
176
177 /*
178 * Shut down the entropy source now so the "stop typing" message
179 * does not muck with the output.
180 */
181 if (entropy_source != NULL)
182 isc_entropy_destroysource(&entropy_source);
183
184 if (key != NULL)
185 dst_key_free(&key);
186
187 isc_entropy_detach(&ectx);
188 dst_lib_destroy();
189 }
190
191 /*%
192 * Write a key file to 'keyfile'. If 'user' is non-NULL,
193 * make that user the owner of the file. The key will have
194 * the name 'keyname' and the secret in the buffer 'secret'.
195 */
196 void
write_key_file(const char * keyfile,const char * user,const char * keyname,isc_buffer_t * secret,dns_secalg_t alg)197 write_key_file(const char *keyfile, const char *user,
198 const char *keyname, isc_buffer_t *secret,
199 dns_secalg_t alg) {
200 isc_result_t result;
201 const char *algname = alg_totext(alg);
202 FILE *fd = NULL;
203
204 DO("create keyfile", isc_file_safecreate(keyfile, &fd));
205
206 if (user != NULL) {
207 if (set_user(fd, user) == -1)
208 fatal("unable to set file owner\n");
209 }
210
211 fprintf(fd, "key \"%s\" {\n\talgorithm %s;\n"
212 "\tsecret \"%.*s\";\n};\n",
213 keyname, algname,
214 (int)isc_buffer_usedlength(secret),
215 (char *)isc_buffer_base(secret));
216 fflush(fd);
217 if (ferror(fd))
218 fatal("write to %s failed\n", keyfile);
219 if (fclose(fd))
220 fatal("fclose(%s) failed\n", keyfile);
221 fprintf(stderr, "wrote key file \"%s\"\n", keyfile);
222 }
223
224