xref: /netbsd/external/mpl/bind/dist/bin/confgen/keygen.c (revision c0b5d9fb)
1 /*	$NetBSD: keygen.c,v 1.6 2022/09/23 12:15:20 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include "keygen.h"
19 #include <stdarg.h>
20 #include <stdlib.h>
21 
22 #include <isc/base64.h>
23 #include <isc/buffer.h>
24 #include <isc/file.h>
25 #include <isc/mem.h>
26 #include <isc/print.h>
27 #include <isc/result.h>
28 #include <isc/string.h>
29 
30 #include <pk11/site.h>
31 
32 #include <dns/keyvalues.h>
33 #include <dns/name.h>
34 
35 #include <dst/dst.h>
36 
37 #include <confgen/os.h>
38 
39 #include "util.h"
40 
41 /*%
42  * Convert algorithm type to string.
43  */
44 const char *
alg_totext(dns_secalg_t alg)45 alg_totext(dns_secalg_t alg) {
46 	switch (alg) {
47 	case DST_ALG_HMACMD5:
48 		return ("hmac-md5");
49 	case DST_ALG_HMACSHA1:
50 		return ("hmac-sha1");
51 	case DST_ALG_HMACSHA224:
52 		return ("hmac-sha224");
53 	case DST_ALG_HMACSHA256:
54 		return ("hmac-sha256");
55 	case DST_ALG_HMACSHA384:
56 		return ("hmac-sha384");
57 	case DST_ALG_HMACSHA512:
58 		return ("hmac-sha512");
59 	default:
60 		return ("(unknown)");
61 	}
62 }
63 
64 /*%
65  * Convert string to algorithm type.
66  */
67 dns_secalg_t
alg_fromtext(const char * name)68 alg_fromtext(const char *name) {
69 	const char *p = name;
70 	if (strncasecmp(p, "hmac-", 5) == 0) {
71 		p = &name[5];
72 	}
73 
74 	if (strcasecmp(p, "md5") == 0) {
75 		return (DST_ALG_HMACMD5);
76 	}
77 	if (strcasecmp(p, "sha1") == 0) {
78 		return (DST_ALG_HMACSHA1);
79 	}
80 	if (strcasecmp(p, "sha224") == 0) {
81 		return (DST_ALG_HMACSHA224);
82 	}
83 	if (strcasecmp(p, "sha256") == 0) {
84 		return (DST_ALG_HMACSHA256);
85 	}
86 	if (strcasecmp(p, "sha384") == 0) {
87 		return (DST_ALG_HMACSHA384);
88 	}
89 	if (strcasecmp(p, "sha512") == 0) {
90 		return (DST_ALG_HMACSHA512);
91 	}
92 	return (DST_ALG_UNKNOWN);
93 }
94 
95 /*%
96  * Return default keysize for a given algorithm type.
97  */
98 int
alg_bits(dns_secalg_t alg)99 alg_bits(dns_secalg_t alg) {
100 	switch (alg) {
101 	case DST_ALG_HMACMD5:
102 		return (128);
103 	case DST_ALG_HMACSHA1:
104 		return (160);
105 	case DST_ALG_HMACSHA224:
106 		return (224);
107 	case DST_ALG_HMACSHA256:
108 		return (256);
109 	case DST_ALG_HMACSHA384:
110 		return (384);
111 	case DST_ALG_HMACSHA512:
112 		return (512);
113 	default:
114 		return (0);
115 	}
116 }
117 
118 /*%
119  * Generate a key of size 'keysize' and place it in 'key_txtbuffer'
120  */
121 void
generate_key(isc_mem_t * mctx,dns_secalg_t alg,int keysize,isc_buffer_t * key_txtbuffer)122 generate_key(isc_mem_t *mctx, dns_secalg_t alg, int keysize,
123 	     isc_buffer_t *key_txtbuffer) {
124 	isc_result_t result = ISC_R_SUCCESS;
125 	isc_buffer_t key_rawbuffer;
126 	isc_region_t key_rawregion;
127 	char key_rawsecret[64];
128 	dst_key_t *key = NULL;
129 
130 	switch (alg) {
131 	case DST_ALG_HMACMD5:
132 	case DST_ALG_HMACSHA1:
133 	case DST_ALG_HMACSHA224:
134 	case DST_ALG_HMACSHA256:
135 		if (keysize < 1 || keysize > 512) {
136 			fatal("keysize %d out of range (must be 1-512)\n",
137 			      keysize);
138 		}
139 		break;
140 	case DST_ALG_HMACSHA384:
141 	case DST_ALG_HMACSHA512:
142 		if (keysize < 1 || keysize > 1024) {
143 			fatal("keysize %d out of range (must be 1-1024)\n",
144 			      keysize);
145 		}
146 		break;
147 	default:
148 		fatal("unsupported algorithm %d\n", alg);
149 	}
150 
151 	DO("initialize dst library", dst_lib_init(mctx, NULL));
152 
153 	DO("generate key",
154 	   dst_key_generate(dns_rootname, alg, keysize, 0, 0, DNS_KEYPROTO_ANY,
155 			    dns_rdataclass_in, mctx, &key, NULL));
156 
157 	isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
158 
159 	DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer));
160 
161 	isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
162 
163 	DO("bsse64 encode secret",
164 	   isc_base64_totext(&key_rawregion, -1, "", key_txtbuffer));
165 
166 	if (key != NULL) {
167 		dst_key_free(&key);
168 	}
169 
170 	dst_lib_destroy();
171 }
172 
173 /*%
174  * Write a key file to 'keyfile'.  If 'user' is non-NULL,
175  * make that user the owner of the file.  The key will have
176  * the name 'keyname' and the secret in the buffer 'secret'.
177  */
178 void
write_key_file(const char * keyfile,const char * user,const char * keyname,isc_buffer_t * secret,dns_secalg_t alg)179 write_key_file(const char *keyfile, const char *user, const char *keyname,
180 	       isc_buffer_t *secret, dns_secalg_t alg) {
181 	isc_result_t result;
182 	const char *algname = alg_totext(alg);
183 	FILE *fd = NULL;
184 
185 	DO("create keyfile", isc_file_safecreate(keyfile, &fd));
186 
187 	if (user != NULL) {
188 		if (set_user(fd, user) == -1) {
189 			fatal("unable to set file owner\n");
190 		}
191 	}
192 
193 	fprintf(fd,
194 		"key \"%s\" {\n\talgorithm %s;\n"
195 		"\tsecret \"%.*s\";\n};\n",
196 		keyname, algname, (int)isc_buffer_usedlength(secret),
197 		(char *)isc_buffer_base(secret));
198 	fflush(fd);
199 	if (ferror(fd)) {
200 		fatal("write to %s failed\n", keyfile);
201 	}
202 	if (fclose(fd)) {
203 		fatal("fclose(%s) failed\n", keyfile);
204 	}
205 	fprintf(stderr, "wrote key file \"%s\"\n", keyfile);
206 }
207