keygen.c revision 254402
1/* 2 * Copyright (C) 2009, 2012, 2013 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id: keygen.c,v 1.4 2009/11/12 14:02:38 marka Exp $ */ 18 19/*! \file */ 20 21#include <config.h> 22 23#include <stdlib.h> 24#include <stdarg.h> 25 26#include <isc/base64.h> 27#include <isc/buffer.h> 28#include <isc/entropy.h> 29#include <isc/file.h> 30#include <isc/keyboard.h> 31#include <isc/mem.h> 32#include <isc/result.h> 33#include <isc/string.h> 34 35#include <dns/keyvalues.h> 36#include <dns/name.h> 37 38#include <dst/dst.h> 39#include <confgen/os.h> 40 41#include "util.h" 42#include "keygen.h" 43 44/*% 45 * Convert algorithm type to string. 46 */ 47const char * 48alg_totext(dns_secalg_t alg) { 49 switch (alg) { 50 case DST_ALG_HMACMD5: 51 return "hmac-md5"; 52 case DST_ALG_HMACSHA1: 53 return "hmac-sha1"; 54 case DST_ALG_HMACSHA224: 55 return "hmac-sha224"; 56 case DST_ALG_HMACSHA256: 57 return "hmac-sha256"; 58 case DST_ALG_HMACSHA384: 59 return "hmac-sha384"; 60 case DST_ALG_HMACSHA512: 61 return "hmac-sha512"; 62 default: 63 return "(unknown)"; 64 } 65} 66 67/*% 68 * Convert string to algorithm type. 69 */ 70dns_secalg_t 71alg_fromtext(const char *name) { 72 if (strcmp(name, "hmac-md5") == 0) 73 return DST_ALG_HMACMD5; 74 if (strcmp(name, "hmac-sha1") == 0) 75 return DST_ALG_HMACSHA1; 76 if (strcmp(name, "hmac-sha224") == 0) 77 return DST_ALG_HMACSHA224; 78 if (strcmp(name, "hmac-sha256") == 0) 79 return DST_ALG_HMACSHA256; 80 if (strcmp(name, "hmac-sha384") == 0) 81 return DST_ALG_HMACSHA384; 82 if (strcmp(name, "hmac-sha512") == 0) 83 return DST_ALG_HMACSHA512; 84 return DST_ALG_UNKNOWN; 85} 86 87/*% 88 * Return default keysize for a given algorithm type. 89 */ 90int 91alg_bits(dns_secalg_t alg) { 92 switch (alg) { 93 case DST_ALG_HMACMD5: 94 return 128; 95 case DST_ALG_HMACSHA1: 96 return 160; 97 case DST_ALG_HMACSHA224: 98 return 224; 99 case DST_ALG_HMACSHA256: 100 return 256; 101 case DST_ALG_HMACSHA384: 102 return 384; 103 case DST_ALG_HMACSHA512: 104 return 512; 105 default: 106 return 0; 107 } 108} 109 110/*% 111 * Generate a key of size 'keysize' using entropy source 'randomfile', 112 * and place it in 'key_txtbuffer' 113 */ 114void 115generate_key(isc_mem_t *mctx, const char *randomfile, dns_secalg_t alg, 116 int keysize, isc_buffer_t *key_txtbuffer) { 117 isc_result_t result = ISC_R_SUCCESS; 118 isc_entropysource_t *entropy_source = NULL; 119 int open_keyboard = ISC_ENTROPY_KEYBOARDMAYBE; 120 int entropy_flags = 0; 121 isc_entropy_t *ectx = NULL; 122 isc_buffer_t key_rawbuffer; 123 isc_region_t key_rawregion; 124 char key_rawsecret[64]; 125 dst_key_t *key = NULL; 126 127 switch (alg) { 128 case DST_ALG_HMACMD5: 129 case DST_ALG_HMACSHA1: 130 case DST_ALG_HMACSHA224: 131 case DST_ALG_HMACSHA256: 132 if (keysize < 1 || keysize > 512) 133 fatal("keysize %d out of range (must be 1-512)\n", 134 keysize); 135 break; 136 case DST_ALG_HMACSHA384: 137 case DST_ALG_HMACSHA512: 138 if (keysize < 1 || keysize > 1024) 139 fatal("keysize %d out of range (must be 1-1024)\n", 140 keysize); 141 break; 142 default: 143 fatal("unsupported algorithm %d\n", alg); 144 } 145 146 147 DO("create entropy context", isc_entropy_create(mctx, &ectx)); 148 149 if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { 150 randomfile = NULL; 151 open_keyboard = ISC_ENTROPY_KEYBOARDYES; 152 } 153 DO("start entropy source", isc_entropy_usebestsource(ectx, 154 &entropy_source, 155 randomfile, 156 open_keyboard)); 157 158 entropy_flags = ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY; 159 160 DO("initialize dst library", dst_lib_init(mctx, ectx, entropy_flags)); 161 162 DO("generate key", dst_key_generate(dns_rootname, alg, 163 keysize, 0, 0, 164 DNS_KEYPROTO_ANY, 165 dns_rdataclass_in, mctx, &key)); 166 167 isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret)); 168 169 DO("dump key to buffer", dst_key_tobuffer(key, &key_rawbuffer)); 170 171 isc_buffer_usedregion(&key_rawbuffer, &key_rawregion); 172 173 DO("bsse64 encode secret", isc_base64_totext(&key_rawregion, -1, "", 174 key_txtbuffer)); 175 176 /* 177 * Shut down the entropy source now so the "stop typing" message 178 * does not muck with the output. 179 */ 180 if (entropy_source != NULL) 181 isc_entropy_destroysource(&entropy_source); 182 183 if (key != NULL) 184 dst_key_free(&key); 185 186 isc_entropy_detach(&ectx); 187 dst_lib_destroy(); 188} 189 190/*% 191 * Write a key file to 'keyfile'. If 'user' is non-NULL, 192 * make that user the owner of the file. The key will have 193 * the name 'keyname' and the secret in the buffer 'secret'. 194 */ 195void 196write_key_file(const char *keyfile, const char *user, 197 const char *keyname, isc_buffer_t *secret, 198 dns_secalg_t alg) { 199 isc_result_t result; 200 const char *algname = alg_totext(alg); 201 FILE *fd = NULL; 202 203 DO("create keyfile", isc_file_safecreate(keyfile, &fd)); 204 205 if (user != NULL) { 206 if (set_user(fd, user) == -1) 207 fatal("unable to set file owner\n"); 208 } 209 210 fprintf(fd, "key \"%s\" {\n\talgorithm %s;\n" 211 "\tsecret \"%.*s\";\n};\n", 212 keyname, algname, 213 (int)isc_buffer_usedlength(secret), 214 (char *)isc_buffer_base(secret)); 215 fflush(fd); 216 if (ferror(fd)) 217 fatal("write to %s failed\n", keyfile); 218 if (fclose(fd)) 219 fatal("fclose(%s) failed\n", keyfile); 220 fprintf(stderr, "wrote key file \"%s\"\n", keyfile); 221} 222 223