1 /* $NetBSD: tsigconf.c,v 1.6 2022/09/23 12:15:21 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/string.h> 24 #include <isc/util.h> 25 26 #include <dns/result.h> 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_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 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 isc_stdtime_get(&now); 109 ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, 110 false, NULL, now, now, mctx, ring, 111 &tsigkey); 112 isc_mem_put(mctx, secret, secretalloc); 113 secret = NULL; 114 if (ret != ISC_R_SUCCESS) { 115 goto failure; 116 } 117 /* 118 * Set digest bits. 119 */ 120 dst_key_setbits(tsigkey->key, bits); 121 dns_tsigkey_detach(&tsigkey); 122 } 123 124 return (ISC_R_SUCCESS); 125 126 failure: 127 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR, 128 "configuring key '%s': %s", keyid, isc_result_totext(ret)); 129 130 if (secret != NULL) { 131 isc_mem_put(mctx, secret, secretalloc); 132 } 133 return (ret); 134 } 135 136 isc_result_t 137 named_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig, 138 isc_mem_t *mctx, dns_tsig_keyring_t **ringp) { 139 const cfg_obj_t *maps[3]; 140 const cfg_obj_t *keylist; 141 dns_tsig_keyring_t *ring = NULL; 142 isc_result_t result; 143 int i; 144 145 REQUIRE(ringp != NULL && *ringp == NULL); 146 147 i = 0; 148 if (config != NULL) { 149 maps[i++] = config; 150 } 151 if (vconfig != NULL) { 152 maps[i++] = cfg_tuple_get(vconfig, "options"); 153 } 154 maps[i] = NULL; 155 156 result = dns_tsigkeyring_create(mctx, &ring); 157 if (result != ISC_R_SUCCESS) { 158 return (result); 159 } 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