1 /* $NetBSD: tsigconf.c,v 1.9 2025/01/26 16:24:33 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 <inttypes.h> 19 20 #include <isc/base64.h> 21 #include <isc/buffer.h> 22 #include <isc/mem.h> 23 #include <isc/result.h> 24 #include <isc/string.h> 25 #include <isc/util.h> 26 27 #include <dns/tsig.h> 28 29 #include <isccfg/cfg.h> 30 31 #include <named/config.h> 32 #include <named/log.h> 33 #include <named/tsigconf.h> 34 35 static isc_result_t 36 add_initial_keys(const cfg_obj_t *list, dns_tsigkeyring_t *ring, 37 isc_mem_t *mctx) { 38 dns_tsigkey_t *tsigkey = NULL; 39 const cfg_listelt_t *element; 40 const cfg_obj_t *key = NULL; 41 const char *keyid = NULL; 42 unsigned char *secret = NULL; 43 int secretalloc = 0; 44 isc_result_t ret; 45 46 for (element = cfg_list_first(list); element != NULL; 47 element = cfg_list_next(element)) 48 { 49 const cfg_obj_t *algobj = NULL; 50 const cfg_obj_t *secretobj = NULL; 51 dns_name_t keyname; 52 dst_algorithm_t alg = DST_ALG_UNKNOWN; 53 const char *algstr = NULL; 54 char keynamedata[1024]; 55 isc_buffer_t keynamesrc, keynamebuf; 56 const char *secretstr = NULL; 57 isc_buffer_t secretbuf; 58 int secretlen = 0; 59 uint16_t bits; 60 61 key = cfg_listelt_value(element); 62 keyid = cfg_obj_asstring(cfg_map_getname(key)); 63 64 algobj = NULL; 65 secretobj = NULL; 66 (void)cfg_map_get(key, "algorithm", &algobj); 67 (void)cfg_map_get(key, "secret", &secretobj); 68 INSIST(algobj != NULL && secretobj != NULL); 69 70 /* 71 * Create the key name. 72 */ 73 dns_name_init(&keyname, NULL); 74 isc_buffer_constinit(&keynamesrc, keyid, strlen(keyid)); 75 isc_buffer_add(&keynamesrc, strlen(keyid)); 76 isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata)); 77 ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname, 78 DNS_NAME_DOWNCASE, &keynamebuf); 79 if (ret != ISC_R_SUCCESS) { 80 goto failure; 81 } 82 83 /* 84 * Create the algorithm. 85 */ 86 algstr = cfg_obj_asstring(algobj); 87 if (named_config_getkeyalgorithm(algstr, &alg, &bits) != 88 ISC_R_SUCCESS) 89 { 90 cfg_obj_log(algobj, named_g_lctx, ISC_LOG_ERROR, 91 "key '%s': has a " 92 "unsupported algorithm '%s'", 93 keyid, algstr); 94 ret = DNS_R_BADALG; 95 goto failure; 96 } 97 98 secretstr = cfg_obj_asstring(secretobj); 99 secretalloc = secretlen = strlen(secretstr) * 3 / 4; 100 secret = isc_mem_get(mctx, secretlen); 101 isc_buffer_init(&secretbuf, secret, secretlen); 102 ret = isc_base64_decodestring(secretstr, &secretbuf); 103 if (ret != ISC_R_SUCCESS) { 104 goto failure; 105 } 106 secretlen = isc_buffer_usedlength(&secretbuf); 107 108 ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, mctx, 109 &tsigkey); 110 isc_mem_put(mctx, secret, secretalloc); 111 secret = NULL; 112 if (ret == ISC_R_SUCCESS) { 113 ret = dns_tsigkeyring_add(ring, tsigkey); 114 } 115 if (ret != ISC_R_SUCCESS) { 116 if (tsigkey != NULL) { 117 dns_tsigkey_detach(&tsigkey); 118 } 119 goto failure; 120 } 121 /* 122 * Set digest bits. 123 */ 124 dst_key_setbits(tsigkey->key, bits); 125 dns_tsigkey_detach(&tsigkey); 126 } 127 128 return ISC_R_SUCCESS; 129 130 failure: 131 if (secret != NULL) { 132 isc_mem_put(mctx, secret, secretalloc); 133 } 134 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, 135 "configuring key '%s': %s", keyid, isc_result_totext(ret)); 136 return ret; 137 } 138 139 isc_result_t 140 named_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, 141 isc_mem_t *mctx, dns_tsigkeyring_t **ringp) { 142 const cfg_obj_t *maps[3]; 143 const cfg_obj_t *keylist; 144 dns_tsigkeyring_t *ring = NULL; 145 isc_result_t result; 146 int i; 147 148 REQUIRE(ringp != NULL && *ringp == NULL); 149 150 i = 0; 151 if (config != NULL) { 152 maps[i++] = config; 153 } 154 if (vconfig != NULL) { 155 maps[i++] = cfg_tuple_get(vconfig, "options"); 156 } 157 maps[i] = NULL; 158 159 dns_tsigkeyring_create(mctx, &ring); 160 161 for (i = 0;; i++) { 162 if (maps[i] == NULL) { 163 break; 164 } 165 keylist = NULL; 166 result = cfg_map_get(maps[i], "key", &keylist); 167 if (result != ISC_R_SUCCESS) { 168 continue; 169 } 170 result = add_initial_keys(keylist, ring, mctx); 171 if (result != ISC_R_SUCCESS) { 172 goto failure; 173 } 174 } 175 176 *ringp = ring; 177 return ISC_R_SUCCESS; 178 179 failure: 180 dns_tsigkeyring_detach(&ring); 181 return result; 182 } 183