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 * 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 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 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 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 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