1224090Sdougb/*
2254402Serwin * Copyright (C) 2009, 2012, 2013  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:
129254402Serwin	    case DST_ALG_HMACSHA1:
130254402Serwin	    case DST_ALG_HMACSHA224:
131254402Serwin	    case DST_ALG_HMACSHA256:
132224090Sdougb		if (keysize < 1 || keysize > 512)
133224090Sdougb			fatal("keysize %d out of range (must be 1-512)\n",
134224090Sdougb			      keysize);
135224090Sdougb		break;
136254402Serwin	    case DST_ALG_HMACSHA384:
137254402Serwin	    case DST_ALG_HMACSHA512:
138254402Serwin		if (keysize < 1 || keysize > 1024)
139254402Serwin			fatal("keysize %d out of range (must be 1-1024)\n",
140224090Sdougb			      keysize);
141224090Sdougb		break;
142224090Sdougb	    default:
143224090Sdougb		fatal("unsupported algorithm %d\n", alg);
144224090Sdougb	}
145224090Sdougb
146224090Sdougb
147224090Sdougb	DO("create entropy context", isc_entropy_create(mctx, &ectx));
148224090Sdougb
149224090Sdougb	if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
150224090Sdougb		randomfile = NULL;
151224090Sdougb		open_keyboard = ISC_ENTROPY_KEYBOARDYES;
152224090Sdougb	}
153224090Sdougb	DO("start entropy source", isc_entropy_usebestsource(ectx,
154224090Sdougb							     &entropy_source,
155224090Sdougb							     randomfile,
156224090Sdougb							     open_keyboard));
157224090Sdougb
158224090Sdougb	entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY;
159224090Sdougb
160224090Sdougb	DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags));
161224090Sdougb
162224090Sdougb	DO("generate key", dst_key_generate(dns_rootname, alg,
163224090Sdougb					    keysize, 0, 0,
164224090Sdougb					    DNS_KEYPROTO_ANY,
165224090Sdougb					    dns_rdataclass_in, mctx, &key));
166224090Sdougb
167224090Sdougb	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
168224090Sdougb
169224090Sdougb	DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer));
170224090Sdougb
171224090Sdougb	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
172224090Sdougb
173224090Sdougb	DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "",
174224090Sdougb						     key_txtbuffer));
175224090Sdougb
176224090Sdougb	/*
177224090Sdougb	 * Shut down the entropy source now so the "stop typing" message
178224090Sdougb	 * does not muck with the output.
179224090Sdougb	 */
180224090Sdougb	if (entropy_source != NULL)
181224090Sdougb		isc_entropy_destroysource(&entropy_source);
182224090Sdougb
183224090Sdougb	if (key != NULL)
184224090Sdougb		dst_key_free(&key);
185224090Sdougb
186224090Sdougb	isc_entropy_detach(&ectx);
187224090Sdougb	dst_lib_destroy();
188224090Sdougb}
189224090Sdougb
190224090Sdougb/*%
191224090Sdougb * Write a key file to 'keyfile'.  If 'user' is non-NULL,
192224090Sdougb * make that user the owner of the file.  The key will have
193224090Sdougb * the name 'keyname' and the secret in the buffer 'secret'.
194224090Sdougb */
195224090Sdougbvoid
196224090Sdougbwrite_key_file(const char *keyfile, const char *user,
197224090Sdougb	       const char *keyname, isc_buffer_t *secret,
198224090Sdougb	       dns_secalg_t alg) {
199224090Sdougb	isc_result_t result;
200224090Sdougb	const char *algname = alg_totext(alg);
201224090Sdougb	FILE *fd = NULL;
202224090Sdougb
203224090Sdougb	DO("create keyfile", isc_file_safecreate(keyfile, &fd));
204224090Sdougb
205224090Sdougb	if (user != NULL) {
206224090Sdougb		if (set_user(fd, user) == -1)
207224090Sdougb			fatal("unable to set file owner\n");
208224090Sdougb	}
209224090Sdougb
210224090Sdougb	fprintf(fd, "key \"%s\" {\n\talgorithm %s;\n"
211224090Sdougb		"\tsecret \"%.*s\";\n};\n",
212224090Sdougb		keyname, algname,
213224090Sdougb		(int)isc_buffer_usedlength(secret),
214224090Sdougb		(char *)isc_buffer_base(secret));
215224090Sdougb	fflush(fd);
216224090Sdougb	if (ferror(fd))
217224090Sdougb		fatal("write to %s failed\n", keyfile);
218224090Sdougb	if (fclose(fd))
219224090Sdougb		fatal("fclose(%s) failed\n", keyfile);
220224090Sdougb	fprintf(stderr, "wrote key file \"%s\"\n", keyfile);
221224090Sdougb}
222224090Sdougb
223