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