1 /* $NetBSD: tsigconf.c,v 1.4 2020/05/24 19:46:12 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 /*! \file */ 15 16 #include <inttypes.h> 17 18 #include <isc/base64.h> 19 #include <isc/buffer.h> 20 #include <isc/mem.h> 21 #include <isc/string.h> 22 #include <isc/util.h> 23 24 #include <dns/result.h> 25 #include <dns/tsig.h> 26 27 #include <isccfg/cfg.h> 28 29 #include <named/config.h> 30 #include <named/log.h> 31 #include <named/tsigconf.h> 32 33 static isc_result_t 34 add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring, 35 isc_mem_t *mctx) { 36 dns_tsigkey_t *tsigkey = NULL; 37 const cfg_listelt_t *element; 38 const cfg_obj_t *key = NULL; 39 const char *keyid = NULL; 40 unsigned char *secret = NULL; 41 int secretalloc = 0; 42 int secretlen = 0; 43 isc_result_t ret; 44 isc_stdtime_t now; 45 uint16_t bits; 46 47 for (element = cfg_list_first(list); element != NULL; 48 element = cfg_list_next(element)) 49 { 50 const cfg_obj_t *algobj = NULL; 51 const cfg_obj_t *secretobj = NULL; 52 dns_name_t keyname; 53 const dns_name_t *alg; 54 const char *algstr; 55 char keynamedata[1024]; 56 isc_buffer_t keynamesrc, keynamebuf; 57 const char *secretstr; 58 isc_buffer_t secretbuf; 59 60 key = cfg_listelt_value(element); 61 keyid = cfg_obj_asstring(cfg_map_getname(key)); 62 63 algobj = NULL; 64 secretobj = NULL; 65 (void)cfg_map_get(key, "algorithm", &algobj); 66 (void)cfg_map_get(key, "secret", &secretobj); 67 INSIST(algobj != NULL && secretobj != NULL); 68 69 /* 70 * Create the key name. 71 */ 72 dns_name_init(&keyname, NULL); 73 isc_buffer_constinit(&keynamesrc, keyid, strlen(keyid)); 74 isc_buffer_add(&keynamesrc, strlen(keyid)); 75 isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata)); 76 ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname, 77 DNS_NAME_DOWNCASE, &keynamebuf); 78 if (ret != ISC_R_SUCCESS) { 79 goto failure; 80 } 81 82 /* 83 * Create the algorithm. 84 */ 85 algstr = cfg_obj_asstring(algobj); 86 if (named_config_getkeyalgorithm(algstr, &alg, &bits) != 87 ISC_R_SUCCESS) { 88 cfg_obj_log(algobj, named_g_lctx, ISC_LOG_ERROR, 89 "key '%s': has a " 90 "unsupported algorithm '%s'", 91 keyid, algstr); 92 ret = DNS_R_BADALG; 93 goto failure; 94 } 95 96 secretstr = cfg_obj_asstring(secretobj); 97 secretalloc = secretlen = strlen(secretstr) * 3 / 4; 98 secret = isc_mem_get(mctx, secretlen); 99 isc_buffer_init(&secretbuf, secret, secretlen); 100 ret = isc_base64_decodestring(secretstr, &secretbuf); 101 if (ret != ISC_R_SUCCESS) { 102 goto failure; 103 } 104 secretlen = isc_buffer_usedlength(&secretbuf); 105 106 isc_stdtime_get(&now); 107 ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, 108 false, NULL, now, now, mctx, ring, 109 &tsigkey); 110 isc_mem_put(mctx, secret, secretalloc); 111 secret = NULL; 112 if (ret != ISC_R_SUCCESS) { 113 goto failure; 114 } 115 /* 116 * Set digest bits. 117 */ 118 dst_key_setbits(tsigkey->key, bits); 119 dns_tsigkey_detach(&tsigkey); 120 } 121 122 return (ISC_R_SUCCESS); 123 124 failure: 125 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, 126 "configuring key '%s': %s", keyid, isc_result_totext(ret)); 127 128 if (secret != NULL) { 129 isc_mem_put(mctx, secret, secretalloc); 130 } 131 return (ret); 132 } 133 134 isc_result_t 135 named_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, 136 isc_mem_t *mctx, dns_tsig_keyring_t **ringp) { 137 const cfg_obj_t *maps[3]; 138 const cfg_obj_t *keylist; 139 dns_tsig_keyring_t *ring = NULL; 140 isc_result_t result; 141 int i; 142 143 REQUIRE(ringp != NULL && *ringp == NULL); 144 145 i = 0; 146 if (config != NULL) { 147 maps[i++] = config; 148 } 149 if (vconfig != NULL) { 150 maps[i++] = cfg_tuple_get(vconfig, "options"); 151 } 152 maps[i] = NULL; 153 154 result = dns_tsigkeyring_create(mctx, &ring); 155 if (result != ISC_R_SUCCESS) { 156 return (result); 157 } 158 159 for (i = 0;; i++) { 160 if (maps[i] == NULL) { 161 break; 162 } 163 keylist = NULL; 164 result = cfg_map_get(maps[i], "key", &keylist); 165 if (result != ISC_R_SUCCESS) { 166 continue; 167 } 168 result = add_initial_keys(keylist, ring, mctx); 169 if (result != ISC_R_SUCCESS) { 170 goto failure; 171 } 172 } 173 174 *ringp = ring; 175 return (ISC_R_SUCCESS); 176 177 failure: 178 dns_tsigkeyring_detach(&ring); 179 return (result); 180 } 181