keygen.c revision 234010
1224090Sdougb/*
2224090Sdougb * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
3224090Sdougb *
4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any
5224090Sdougb * purpose with or without fee is hereby granted, provided that the above
6224090Sdougb * copyright notice and this permission notice appear in all copies.
7224090Sdougb *
8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10224090Sdougb * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14224090Sdougb * PERFORMANCE OF THIS SOFTWARE.
15224090Sdougb */
16224090Sdougb
17234010Sdougb/* $Id: keygen.c,v 1.4 2009/11/12 14:02:38 marka Exp $ */
18224090Sdougb
19224090Sdougb/*! \file */
20224090Sdougb
21224090Sdougb#include <config.h>
22224090Sdougb
23224090Sdougb#include <stdlib.h>
24224090Sdougb#include <stdarg.h>
25224090Sdougb
26224090Sdougb#include <isc/base64.h>
27224090Sdougb#include <isc/buffer.h>
28224090Sdougb#include <isc/entropy.h>
29224090Sdougb#include <isc/file.h>
30224090Sdougb#include <isc/keyboard.h>
31224090Sdougb#include <isc/mem.h>
32224090Sdougb#include <isc/result.h>
33224090Sdougb#include <isc/string.h>
34224090Sdougb
35224090Sdougb#include <dns/keyvalues.h>
36224090Sdougb#include <dns/name.h>
37224090Sdougb
38224090Sdougb#include <dst/dst.h>
39224090Sdougb#include <confgen/os.h>
40224090Sdougb
41224090Sdougb#include "util.h"
42224090Sdougb#include "keygen.h"
43224090Sdougb
44224090Sdougb/*%
45224090Sdougb * Convert algorithm type to string.
46224090Sdougb */
47224090Sdougbconst char *
48224090Sdougbalg_totext(dns_secalg_t alg) {
49224090Sdougb	switch (alg) {
50224090Sdougb	    case DST_ALG_HMACMD5:
51224090Sdougb		return "hmac-md5";
52224090Sdougb	    case DST_ALG_HMACSHA1:
53224090Sdougb		return "hmac-sha1";
54224090Sdougb	    case DST_ALG_HMACSHA224:
55224090Sdougb		return "hmac-sha224";
56224090Sdougb	    case DST_ALG_HMACSHA256:
57224090Sdougb		return "hmac-sha256";
58224090Sdougb	    case DST_ALG_HMACSHA384:
59224090Sdougb		return "hmac-sha384";
60224090Sdougb	    case DST_ALG_HMACSHA512:
61224090Sdougb		return "hmac-sha512";
62224090Sdougb	    default:
63224090Sdougb		return "(unknown)";
64224090Sdougb	}
65224090Sdougb}
66224090Sdougb
67224090Sdougb/*%
68224090Sdougb * Convert string to algorithm type.
69224090Sdougb */
70224090Sdougbdns_secalg_t
71224090Sdougbalg_fromtext(const char *name) {
72224090Sdougb	if (strcmp(name, "hmac-md5") == 0)
73224090Sdougb		return DST_ALG_HMACMD5;
74224090Sdougb	if (strcmp(name, "hmac-sha1") == 0)
75224090Sdougb		return DST_ALG_HMACSHA1;
76224090Sdougb	if (strcmp(name, "hmac-sha224") == 0)
77224090Sdougb		return DST_ALG_HMACSHA224;
78224090Sdougb	if (strcmp(name, "hmac-sha256") == 0)
79224090Sdougb		return DST_ALG_HMACSHA256;
80224090Sdougb	if (strcmp(name, "hmac-sha384") == 0)
81224090Sdougb		return DST_ALG_HMACSHA384;
82224090Sdougb	if (strcmp(name, "hmac-sha512") == 0)
83224090Sdougb		return DST_ALG_HMACSHA512;
84224090Sdougb	return DST_ALG_UNKNOWN;
85224090Sdougb}
86224090Sdougb
87224090Sdougb/*%
88224090Sdougb * Return default keysize for a given algorithm type.
89224090Sdougb */
90224090Sdougbint
91224090Sdougbalg_bits(dns_secalg_t alg) {
92224090Sdougb	switch (alg) {
93224090Sdougb	    case DST_ALG_HMACMD5:
94224090Sdougb		return 128;
95224090Sdougb	    case DST_ALG_HMACSHA1:
96224090Sdougb		return 160;
97224090Sdougb	    case DST_ALG_HMACSHA224:
98224090Sdougb		return 224;
99224090Sdougb	    case DST_ALG_HMACSHA256:
100224090Sdougb		return 256;
101224090Sdougb	    case DST_ALG_HMACSHA384:
102224090Sdougb		return 384;
103224090Sdougb	    case DST_ALG_HMACSHA512:
104224090Sdougb		return 512;
105224090Sdougb	    default:
106224090Sdougb		return 0;
107224090Sdougb	}
108224090Sdougb}
109224090Sdougb
110224090Sdougb/*%
111224090Sdougb * Generate a key of size 'keysize' using entropy source 'randomfile',
112224090Sdougb * and place it in 'key_txtbuffer'
113224090Sdougb */
114224090Sdougbvoid
115224090Sdougbgenerate_key(isc_mem_t *mctx, const char *randomfile, dns_secalg_t alg,
116224090Sdougb	     int keysize, isc_buffer_t *key_txtbuffer) {
117224090Sdougb	isc_result_t result = ISC_R_SUCCESS;
118224090Sdougb	isc_entropysource_t *entropy_source = NULL;
119224090Sdougb	int open_keyboard = ISC_ENTROPY_KEYBOARDMAYBE;
120224090Sdougb	int entropy_flags = 0;
121224090Sdougb	isc_entropy_t *ectx = NULL;
122224090Sdougb	isc_buffer_t key_rawbuffer;
123224090Sdougb	isc_region_t key_rawregion;
124224090Sdougb	char key_rawsecret[64];
125224090Sdougb	dst_key_t *key = NULL;
126224090Sdougb
127224090Sdougb	switch (alg) {
128224090Sdougb	    case DST_ALG_HMACMD5:
129224090Sdougb		if (keysize < 1 || keysize > 512)
130224090Sdougb			fatal("keysize %d out of range (must be 1-512)\n",
131224090Sdougb			      keysize);
132224090Sdougb		break;
133224090Sdougb	    case DST_ALG_HMACSHA256:
134224090Sdougb		if (keysize < 1 || keysize > 256)
135224090Sdougb			fatal("keysize %d out of range (must be 1-256)\n",
136224090Sdougb			      keysize);
137224090Sdougb		break;
138224090Sdougb	    default:
139224090Sdougb		fatal("unsupported algorithm %d\n", alg);
140224090Sdougb	}
141224090Sdougb
142224090Sdougb
143224090Sdougb	DO("create entropy context", isc_entropy_create(mctx, &ectx));
144224090Sdougb
145224090Sdougb	if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
146224090Sdougb		randomfile = NULL;
147224090Sdougb		open_keyboard = ISC_ENTROPY_KEYBOARDYES;
148224090Sdougb	}
149224090Sdougb	DO("start entropy source", isc_entropy_usebestsource(ectx,
150224090Sdougb							     &entropy_source,
151224090Sdougb							     randomfile,
152224090Sdougb							     open_keyboard));
153224090Sdougb
154224090Sdougb	entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY;
155224090Sdougb
156224090Sdougb	DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags));
157224090Sdougb
158224090Sdougb	DO("generate key", dst_key_generate(dns_rootname, alg,
159224090Sdougb					    keysize, 0, 0,
160224090Sdougb					    DNS_KEYPROTO_ANY,
161224090Sdougb					    dns_rdataclass_in, mctx, &key));
162224090Sdougb
163224090Sdougb	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
164224090Sdougb
165224090Sdougb	DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer));
166224090Sdougb
167224090Sdougb	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
168224090Sdougb
169224090Sdougb	DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "",
170224090Sdougb						     key_txtbuffer));
171224090Sdougb
172224090Sdougb	/*
173224090Sdougb	 * Shut down the entropy source now so the "stop typing" message
174224090Sdougb	 * does not muck with the output.
175224090Sdougb	 */
176224090Sdougb	if (entropy_source != NULL)
177224090Sdougb		isc_entropy_destroysource(&entropy_source);
178224090Sdougb
179224090Sdougb	if (key != NULL)
180224090Sdougb		dst_key_free(&key);
181224090Sdougb
182224090Sdougb	isc_entropy_detach(&ectx);
183224090Sdougb	dst_lib_destroy();
184224090Sdougb}
185224090Sdougb
186224090Sdougb/*%
187224090Sdougb * Write a key file to 'keyfile'.  If 'user' is non-NULL,
188224090Sdougb * make that user the owner of the file.  The key will have
189224090Sdougb * the name 'keyname' and the secret in the buffer 'secret'.
190224090Sdougb */
191224090Sdougbvoid
192224090Sdougbwrite_key_file(const char *keyfile, const char *user,
193224090Sdougb	       const char *keyname, isc_buffer_t *secret,
194224090Sdougb	       dns_secalg_t alg) {
195224090Sdougb	isc_result_t result;
196224090Sdougb	const char *algname = alg_totext(alg);
197224090Sdougb	FILE *fd = NULL;
198224090Sdougb
199224090Sdougb	DO("create keyfile", isc_file_safecreate(keyfile, &fd));
200224090Sdougb
201224090Sdougb	if (user != NULL) {
202224090Sdougb		if (set_user(fd, user) == -1)
203224090Sdougb			fatal("unable to set file owner\n");
204224090Sdougb	}
205224090Sdougb
206224090Sdougb	fprintf(fd, "key \"%s\" {\n\talgorithm %s;\n"
207224090Sdougb		"\tsecret \"%.*s\";\n};\n",
208224090Sdougb		keyname, algname,
209224090Sdougb		(int)isc_buffer_usedlength(secret),
210224090Sdougb		(char *)isc_buffer_base(secret));
211224090Sdougb	fflush(fd);
212224090Sdougb	if (ferror(fd))
213224090Sdougb		fatal("write to %s failed\n", keyfile);
214224090Sdougb	if (fclose(fd))
215224090Sdougb		fatal("fclose(%s) failed\n", keyfile);
216224090Sdougb	fprintf(stderr, "wrote key file \"%s\"\n", keyfile);
217224090Sdougb}
218224090Sdougb
219