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