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