1/*
2 * Copyright (C) 2004-2007, 2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: tsigconf.c,v 1.35 2011/01/11 23:47:12 tbox Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <isc/base64.h>
25#include <isc/buffer.h>
26#include <isc/mem.h>
27#include <isc/string.h>
28
29#include <isccfg/cfg.h>
30
31#include <dns/tsig.h>
32#include <dns/result.h>
33
34#include <named/log.h>
35
36#include <named/config.h>
37#include <named/tsigconf.h>
38
39static isc_result_t
40add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring,
41		 isc_mem_t *mctx)
42{
43	dns_tsigkey_t *tsigkey = NULL;
44	const cfg_listelt_t *element;
45	const cfg_obj_t *key = NULL;
46	const char *keyid = NULL;
47	unsigned char *secret = NULL;
48	int secretalloc = 0;
49	int secretlen = 0;
50	isc_result_t ret;
51	isc_stdtime_t now;
52	isc_uint16_t bits;
53
54	for (element = cfg_list_first(list);
55	     element != NULL;
56	     element = cfg_list_next(element))
57	{
58		const cfg_obj_t *algobj = NULL;
59		const cfg_obj_t *secretobj = NULL;
60		dns_name_t keyname;
61		dns_name_t *alg;
62		const char *algstr;
63		char keynamedata[1024];
64		isc_buffer_t keynamesrc, keynamebuf;
65		const char *secretstr;
66		isc_buffer_t secretbuf;
67
68		key = cfg_listelt_value(element);
69		keyid = cfg_obj_asstring(cfg_map_getname(key));
70
71		algobj = NULL;
72		secretobj = NULL;
73		(void)cfg_map_get(key, "algorithm", &algobj);
74		(void)cfg_map_get(key, "secret", &secretobj);
75		INSIST(algobj != NULL && secretobj != NULL);
76
77		/*
78		 * Create the key name.
79		 */
80		dns_name_init(&keyname, NULL);
81		isc_buffer_constinit(&keynamesrc, keyid, strlen(keyid));
82		isc_buffer_add(&keynamesrc, strlen(keyid));
83		isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata));
84		ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname,
85					DNS_NAME_DOWNCASE, &keynamebuf);
86		if (ret != ISC_R_SUCCESS)
87			goto failure;
88
89		/*
90		 * Create the algorithm.
91		 */
92		algstr = cfg_obj_asstring(algobj);
93		if (ns_config_getkeyalgorithm(algstr, &alg, &bits)
94		    != ISC_R_SUCCESS) {
95			cfg_obj_log(algobj, ns_g_lctx, ISC_LOG_ERROR,
96				    "key '%s': has a unsupported algorithm '%s'",
97				    keyid, algstr);
98			ret = DNS_R_BADALG;
99			goto failure;
100		}
101
102		secretstr = cfg_obj_asstring(secretobj);
103		secretalloc = secretlen = strlen(secretstr) * 3 / 4;
104		secret = isc_mem_get(mctx, secretlen);
105		if (secret == NULL) {
106			ret = ISC_R_NOMEMORY;
107			goto failure;
108		}
109		isc_buffer_init(&secretbuf, secret, secretlen);
110		ret = isc_base64_decodestring(secretstr, &secretbuf);
111		if (ret != ISC_R_SUCCESS)
112			goto failure;
113		secretlen = isc_buffer_usedlength(&secretbuf);
114
115		isc_stdtime_get(&now);
116		ret = dns_tsigkey_create(&keyname, alg, secret, secretlen,
117					 ISC_FALSE, NULL, now, now,
118					 mctx, ring, &tsigkey);
119		isc_mem_put(mctx, secret, secretalloc);
120		secret = NULL;
121		if (ret != ISC_R_SUCCESS)
122			goto failure;
123		/*
124		 * Set digest bits.
125		 */
126		dst_key_setbits(tsigkey->key, bits);
127		dns_tsigkey_detach(&tsigkey);
128	}
129
130	return (ISC_R_SUCCESS);
131
132 failure:
133	cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR,
134		    "configuring key '%s': %s", keyid,
135		    isc_result_totext(ret));
136
137	if (secret != NULL)
138		isc_mem_put(mctx, secret, secretalloc);
139	return (ret);
140}
141
142isc_result_t
143ns_tsigkeyring_fromconfig(const cfg_obj_t *config, const cfg_obj_t *vconfig,
144			  isc_mem_t *mctx, dns_tsig_keyring_t **ringp)
145{
146	const cfg_obj_t *maps[3];
147	const cfg_obj_t *keylist;
148	dns_tsig_keyring_t *ring = NULL;
149	isc_result_t result;
150	int i;
151
152	REQUIRE(ringp != NULL && *ringp == NULL);
153
154	i = 0;
155	if (config != NULL)
156		maps[i++] = config;
157	if (vconfig != NULL)
158		maps[i++] = cfg_tuple_get(vconfig, "options");
159	maps[i] = NULL;
160
161	result = dns_tsigkeyring_create(mctx, &ring);
162	if (result != ISC_R_SUCCESS)
163		return (result);
164
165	for (i = 0; ; i++) {
166		if (maps[i] == NULL)
167			break;
168		keylist = NULL;
169		result = cfg_map_get(maps[i], "key", &keylist);
170		if (result != ISC_R_SUCCESS)
171			continue;
172		result = add_initial_keys(keylist, ring, mctx);
173		if (result != ISC_R_SUCCESS)
174			goto failure;
175	}
176
177	*ringp = ring;
178	return (ISC_R_SUCCESS);
179
180 failure:
181	dns_tsigkeyring_detach(&ring);
182	return (result);
183}
184